Dataloader is a utility from Facebook to "reduce requests to the backends via batching and caching".
It combines all individuals loads within a single frame of execution (a single tick of the event loop) and then calls its batch function with all requested keys, making sure we don't hit the backend asking for the same key twice.
Although Dataloader has a memoization cache for all loads which occur in a single request, it is not meant to be used as a cache layer. As it excplicitly says, Dataloader "is a data loading mechanism, and its cache only serves the purpose of not repeatedly loading the same data in the context of a single request to your Application".
How it works
On each request of your application you create a new instance of Dataloader. Gstore provides a method for that createDataLoader()
gstore.createDataLoader()
createDataLoader() is a helper to create a Dataloader instance with a batch function that works with the Google Datastore.
You will need to create a new Dataloader instance for each request, and pass it to gstore methods as an option property.
If you only had this piece of code then the Dataloader would not be of much help. Let's see with a more complex example
// images.jsconstImage=require('./image.model');constgetImage= (id, dataloader) => {returnImage.get(id,null,null,null, { dataloader });};module.exports= { getImage };// -------------// users.jsconstUser=require('./user.model');constgetUser= (id, dataloader) => {returnUser.get(id,null,null,null, { dataloader }); };module.exports= { getUser };// -------------/** * The above 2 files don't know about each other (and should not). * In our book route handler we need to fetch the book and then its author + cover image */const { instances } =require('gstore-node');constimages=require('../images/images');constusers=require('../images/images');constBook=require('./book.model');constgstore=instances.get('default');constgetBook= (req, res) => {constdataloader=gstore.createDataLoader();Book.get(req.params.id,null,null,null, { dataloader }).then((book) => (Promise.all([// Those 2 loads will be combined and only 1 request will hit the Datastoreimages.getImage(book.cover, dataloader),users.getUser(book.author, dataloader), ]).then((entities) => {book.cover = entities[0];book.author = entities[1];res.json(book); }); )); };
Dataloader memoization cache
To understand memoization, let's see it with another example.
constPost=require('./posts.model');// dataloader is passed from the request to our getPost() methodconstgetPost=async(id, dataloader) => {constpost=awaitPost.get(id,null,null,null, { dataloader });constuser=awaitpost.model('User').get(post.author,null,null,null, { dataloader });console.log(user.id); // 123post.author = user;return post;};// ...// Elsewhere in your applicationconstUser=require('.users.model');// the same instance of dataloader is passed to updateUser()constupdateUser= (id, data, dataloader) => {console.log(id); // 123 (same user as above);/** * Dataloader already has the user with id "123" in its memoization cache * so during the entity update gstore won't hit the Datastore to fetch the entity * before updating its data. * gstore automaticaly clears the memoization cache after the entity has been updated. */returnUser.update(id, data,null,null,null, { dataloader })};