Reducing database queries to a minimum with DataLoaders
sixfold.medium.com
sixfold.medium.com
I haven't used GraphQL much but things like this make it seem that it's not a great general use case framework- if you don't really need it, save yourself from a bunch of extra logic in your application code.
GraphQL isn't exclusive to databases.
I also have a couple of small helper functions for generating data loaders; I'll edit this comment and post them in a min when I'm back on my laptop.
const oneToOne = (foreign, fn) => new Dataloader(async (keys) => {
const results = await fn(keys);
const index = {};
for(const result of results) {
index[result.get(foreign)] = result;
}
return keys.map(key => key in index ? index[key] : null);
});
const oneToMany = (foreign, fn) => new Dataloader(async (keys) => {
const results = await fn(keys);
const index = {};
for(const result of results) {
const foreignKey = result.get(foreign);
if(!(foreignKey in index)) {
index[foreignKey] = [];
}
index[foreignKey].push(result);
}
return keys.map(key => key in index ? index[key] : []);
});looks nice.
In some projects of mine I've taken advantage of this extra available context to make the most efficient bulk database query or REST API call based on the full query, instead of just the subset of input typically used by the resolver.
E.g. you have IDs for a heterogeneous collection of items, all of them have an owning user, some need additional lookups in type specific tables, some have comments which again have an attached user each. Each lookup should be done towards a cache like Memcached and then a SQL database for any entries not in cache.
If you want to batch those cache calls together as best possible you end up with some fairly ugly code. But with dataloader you can write nice and sequential code dealing with a single item at a time - try loading the item from cache, if not try the database, if found load related data, if not return not found.
Particularly with normalized data, I’ve found it quite common that 80% of my data for some workflows is highly predictable but that last 20% that makes the interaction unique either causes the request to become whole cloth or results in very complicated code, sometimes with very bad (worse than nothing) cold cache behavior.