@@ -452,6 +452,86 @@ Promise.all([ promise1, promise2 ]).then(([ user1, user2]) => {
452452});
453453```
454454
455+ #### RethinkDb
456+
457+ RethinkDb offers a batching method called ` getAll ` but there are a few caveats :
458+ * Order of results is not guaranteed ([ rethinkdb/rethinkdb #5187 ] [ rethinkdb_5187 ] )
459+ * Non-existent keys will not return and empty record
460+ Assuming a table ` example_table ` with those records :
461+ ``` js
462+ [
463+ {" id" : 1 , " name" : " Document 1" },
464+ {" id" : 2 , " name" : " Document 2" }
465+ ]
466+ ```
467+ A query ` r.getAll(1, 2, 3) ` could return such an array :
468+ ``` js
469+ [
470+ {" id" : 2 , " name" : " Document 2" },
471+ {" id" : 1 , " name" : " Document 1" }
472+ ]
473+ ```
474+
475+ In essence, this naive implementation won't work :
476+ ``` js
477+ var r = require (' rethinkdb' );
478+ var db = await r .connect ();
479+
480+ var batchLoadFn = keys => db .table (' example_table' ).getAll (... keys).then (res => res .toArray ());
481+ var exampleLoader = new DataLoader (batchLoadFn);
482+
483+ await exampleLoader .loadMany ([1 , 2 , 3 ]); // Throws, values length !== keys length
484+
485+ await exampleLoader .loadMany ([1 , 2 ]);
486+ await exampleLoader .load (1 ); // {"id": 2, "name": "Document 2"}
487+ ```
488+
489+ A solution is to normalize results returned by ` getAll ` to match the structure of supplied ` keys ` .
490+
491+ To achieve this efficiently, we first write an indexing function. This function will return a Map indexing results.
492+ Parameters :
493+ * ` results ` : Array of RethinkDb results
494+ * ` indexField ` : String indicating which field was used as index for this batch query
495+ * ` cacheKeyFn ` : Optional function used to serialize non-scalar index field values
496+ ``` js
497+ function indexResults (results , indexField , cacheKeyFn = key => key ) {
498+ var indexedResults = new Map ();
499+ results .forEach (res => {
500+ indexedResults .set (cacheKeyFn (res[indexField]), res);
501+ });
502+ return indexedResults;
503+ }
504+ ```
505+ Then, we can leverage our Map to normalize RethinkDb results with another utility function which will produce a normalizing function.
506+ ``` js
507+ function normalizeRethinkDbResults (keys , indexField , cacheKeyFn = key => key ) {
508+ return results => {
509+ var indexedResults = indexResults (results, indexField, cacheKeyFn);
510+ return keys .map (val => indexedResults .get (cacheKeyFn (val)) || new Error (` Key not found : ${ val} ` ));
511+ }
512+ }
513+ ```
514+
515+ Full dataloader implementation :
516+ ``` js
517+ var r = require (' rethinkdb' );
518+ var db = await r .connect ();
519+
520+ var batchLoadFn = keys => db .table (' example_table' )
521+ .getAll (... keys)
522+ .then (res => res .toArray ())
523+ .then (normalizeRethinkDbResults (keys, ' id' ));
524+
525+ var exampleLoader = new DataLoader (batchLoadFn);
526+
527+ await exampleLoader .loadMany ([1 , 2 , 3 ]); // [{"id": 1, "name": "Document 1"}, {"id": 2, "name": "Document 2"}, Error];
528+
529+ await exampleLoader .load (1 ); // {"id": 1, "name": "Document 1"}
530+ ```
531+
532+
533+
534+
455535## Video Source Code Walkthrough
456536
457537** DataLoader Source Code Walkthrough (YouTube):**
@@ -468,3 +548,4 @@ Promise.all([ promise1, promise2 ]).then(([ user1, user2]) => {
468548[ node_redis ] : https://github.com/NodeRedis/node_redis
469549[ nano ] : https://github.com/dscape/nano
470550[ sqlite3 ] : https://github.com/mapbox/node-sqlite3
551+ [ rethinkdb_5187 ] : https://github.com/rethinkdb/rethinkdb/issues/5187
0 commit comments