Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose multiple deep populates

Say, I have Manager schema:

{
    name: { type: String },
    clients: [{ type: Mongoose.Schema.ObjectId, ref: 'Client'}]
}

And, I have Client schema:

{
    name  : { type String },
    cars  : [{ type: Mongoose.Schema.ObjectId, ref: 'Car' }],
    houses: [{ type: Mongoose.Schema.ObjectId, ref: 'House' }]
}

And Car and House as well (their structure is not important for the matter. How do I deep populate multiple Client's fields in the single .populate() call?

What have I tried:

Manager.find()
    .populate({
         path: 'users',
         populate: { path: 'cars' },
         populate: { path: 'houses' }
    });

and it would truly surprise me if it worked (as I overwrite previously declared populate key passed to the .populate() method). My example obviously returns populated houses field per user - the one which comes last. Honestly, no idea, nothing in the docs either. Is it even supported? I know it is for 'shallow' populate, based on my example:

User.populate('cars')
    .populate('houses')

What about the deep one?

like image 322
wscourge Avatar asked Sep 01 '17 13:09

wscourge


People also ask

How do mongooses make relationships?

To model relationships between connected data, you can reference a document or embed it in another document as a sub document. Referencing a document does not create a “real” relationship between these two documents as does with a relational database. Referencing documents is also known as normalization.

What is execPopulate?

execPopulate is method on document, while . populate works on query object. Follow this answer to receive notifications.

What is __ V in MongoDB?

The __v field is called the version key. It describes the internal revision of a document. This __v field is used to track the revisions of a document. By default, its value is zero ( __v:0 ).


1 Answers

1) Pass an array of objects with properties to be populated:

Manager.find()
    .populate({
         path    : 'users',
         populate: [
             { path: 'cars' },
             { path: 'houses' }
         ]
    });

This solution enables to use deep populate to its full extent. Consider:

Manager.find()
    .populate({
         path    : 'users',
         populate: [
             { path: 'cars' },
             { 
                path    : 'houses',
                populate: {
                    path    : 'rooms',
                    populate: 'windows'
                }
             }
         ]
    });

2) Pass string of space-delimited collections to be populated:

Manager.find()
    .populate({
         path    : 'users',
         populate: 'cars houses'
    });
like image 105
wscourge Avatar answered Sep 25 '22 03:09

wscourge