Skip to content

Latest commit

 

History

History
95 lines (74 loc) · 2.63 KB

RethinkDB.md

File metadata and controls

95 lines (74 loc) · 2.63 KB

RethinkDb

RethinkDb offers a batching method called getAll but there are a few caveats :

For example, against a table example_table with these records:

[
  {"id": 1, "name": "Document 1"},
  {"id": 2, "name": "Document 2"}
]

A query r.getAll(1, 2, 3) could return:

[
  {"id": 2, "name": "Document 2"},
  {"id": 1, "name": "Document 1"}
]

Because query keys and values are associated by position in the dataloader cache, this naive implementation won't work (with the same table as above):

const r = require('rethinkdb');
const db = await r.connect();

const exampleLoader = new DataLoader(async keys => {
  const result = await db.table('example_table').getAll(...keys)
  return result.toArray()
})

await exampleLoader.loadMany([1, 2, 3]); // Throws (values length !== keys length)

await exampleLoader.loadMany([1, 2]);
await exampleLoader.load(1); // {"id": 2, "name": "Document 2"}

A solution is to normalize results returned by getAll to match the structure of supplied keys.

To achieve this efficiently, we first write an indexing function. This function will return a Map indexing results.

Parameters:

  • results: Array of RethinkDb results
  • indexField: String indicating which field was used as index for this batch query
  • cacheKeyFn: Optional function used to serialize non-scalar index field values
function indexResults(results, indexField, cacheKeyFn = key => key) {
  const indexedResults = new Map();
  results.forEach(res => {
    indexedResults.set(cacheKeyFn(res[indexField]), res);
  });
  return indexedResults;
}

Then, we can leverage our Map to normalize RethinkDb results with another utility function which will produce a normalizing function.

function normalizeRethinkDbResults(keys, indexField, cacheKeyFn = key => key) {
  return results => {
    const indexedResults = indexResults(results, indexField, cacheKeyFn);
    return keys.map(
      val => indexedResults.get(cacheKeyFn(val))
        || new Error(`Key not found : ${val}`)
    );
  }
}

Full dataloader implementation:

const r = require('rethinkdb');
const db = await r.connect();

const exampleLoader = new DataLoader(async keys => {
  const results = await db.table('example_table').getAll(...keys)
  return normalizeRethinkDbResults(res.toArray(), 'id')
})

// [{"id": 1, "name": "Document 1"}, {"id": 2, "name": "Document 2"}, Error];
await exampleLoader.loadMany([1, 2, 3]);

// {"id": 1, "name": "Document 1"}
await exampleLoader.load(1);