Populate

Gstore supports populate() which lets you reference other entities in your Schemas and easily fetch them and merge their data whenever needed. Population automatically replaces the specified paths in an entity with the data from other entities. We may populate a single entity, multiple entities, or all the entites returned from a query. We can even populate nested entities. Let's look at some examples.

Declare references on your Schemas

The first thing to do is to add some Key references to our Schemas.

const { Schema } = gstore;

const addressSchema = new Schema({ city: { type: String }, country: { type: String } });
const blogSchema = new Schema({ title: { type: String } });
const userSchema = new Schema({
    name: { type: String },
    email: { type: String, validate: 'isEmail' },
    address: { type: Schema.Types.Key, ref: 'Address' }, // references an Address
});
const postSchema = new Schema({
    title: { type: String },
    author: { type: Schema.Types.Key, ref: 'User' } // references a User
    blog: { type: Schema.Types.Key, ref: 'Blog' } // references a Blog
});

const Address = gstore.model('Address', addressSchema);
const Blog = gstore.model('Blog', blogSchema);
const User = gstore.model('User', userSchema);
const Post = gstore.model('Post', postSchema);

Save the entities with references

Let's then save some entities, providing the entity Key as reference.

Populate on Model.get()

Populate 1 reference

In the example below, let's assume that the post we have just saved received the 123 generated ID from the Datastore.

Populate nested references

What if we also want to fetch the "address" from the user at the same time?

We don't have to add the intermediate levels if we are only interested in a nested level.

Chain populate() calls

We can chain populate() calls to fetch multiple references

Or shorter by providing an array of references.

And if you want to fetch all the references on an entity, you can simply call populate() withouth specifying any references. All the properties on your Schema that have their type set as Schema.Types.Key will be fetched.

It also works when providing multiple IDs

Specify the properties to return

populate() accepts a second argument to specify one or multiple properties to be returned from the reference entity.

Important: You can't provide specific properties if you have passed an array of references as first argument.

Populate on queries

The real power of populate() comes with queries as it allows you to very easily join entities data, similar to a "Left Join" in SQL. gstore uses Dataloader to fetch all the entities by keys in one call. Using Dataloader means that if multiple entities returned by the query have references pointing to the same entity Key, only 1 Key will be sent to Datastore.get() and fetched from the Datastore. It also means that the entities fetched are memoized and returned from cache if the reference Key is the same at different "depth" of the tree traversal. This not only means faster retrieval time but only some nice savings on your Datastore billing at the end of the month!

Let's look at some examples.

For the 2 "books" + its "collection" + the "author" of the books and the collections, only 3 keys where fetched from the Datastore: ['User', 1], ['User', 2], ['Collection', 1].

Of course, if you have activated the cache with a Redis store, it would be 0 keys fetched the second time that this query is executed, until a "User", "Post" or "Collection" is added/updated or removed.

Important: The maxium Keys allowed for a Lookup operation is 1,000. With populate(), this corresponds to the maximum number of distinct entity references at one "depth" of the entity data tree. Thanks to the Dataloader and cache, this limit should be hard to reach in most use cases. (View the Datastore limitations)

Model.list(), .findAround(), .findOne(), .query()

All the different gstore queries support the populate() chaining calls with the same arguments that we have seen in previous examples.

Populate on an Entity instance

Finally, Entity instances have also a populate() method that you can call to quickly fetch all the entity references. Like any other populate() that we have seen above, it takes 2 arguments: the "references" to fetch and the "properties" to return from each entity reference.

Last updated

Was this helpful?