24

Assuming the following 3 models:

var CarSchema = new Schema({ name: {type: String}, partIds: [{type: Schema.Types.ObjectId, ref: 'Part'}], }); var PartSchema = new Schema({ name: {type: String}, otherIds: [{type: Schema.Types.ObjectId, ref: 'Other'}], }); var OtherSchema = new Schema({ name: {type: String} }); 

When I query for Cars I can populate the parts:

Car.find().populate('partIds').exec(function(err, cars) { // list of cars with partIds populated }); 

Is there a way in mongoose to populate the otherIds in the nested parts objects for all the cars.

Car.find().populate('partIds').exec(function(err, cars) { // list of cars with partIds populated // Try an populate nested Part.populate(cars, {path: 'partIds.otherIds'}, function(err, cars) { // This does not populate all the otherIds within each part for each car }); }); 

I can probably iterate over each car and try to populate:

Car.find().populate('partIds').exec(function(err, cars) { // list of cars with partIds populated // Iterate all cars cars.forEach(function(car) { Part.populate(car, {path: 'partIds.otherIds'}, function(err, cars) { // This does not populate all the otherIds within each part for each car }); }); }); 

Problem there is that I have to use a lib like async to make the populate call for each and wait until all are done and then return.

Possible to do without looping over all cars?

0

4 Answers 4

45

Update: Please see Trinh Hoang Nhu's answer for a more compact version that was added in Mongoose 4. Summarized below:

Car .find() .populate({ path: 'partIds', model: 'Part', populate: { path: 'otherIds', model: 'Other' } }) 

Mongoose 3 and below:

Car .find() .populate('partIds') .exec(function(err, docs) { if(err) return callback(err); Car.populate(docs, { path: 'partIds.otherIds', model: 'Other' }, function(err, cars) { if(err) return callback(err); console.log(cars); // This object should now be populated accordingly. }); }); 

For nested populations like this, you have to tell mongoose the Schema you want to populate from.

Sign up to request clarification or add additional context in comments.

6 Comments

Crap RTFM ;) I see that now. However no matter what I try I get back an empty array for otherIds. As a sanity check If I don't call the populate method there is an array of id's (which is correct). Populate is not populating those ids. Running 3.8.22 lastest from npm
Also have logging turned on. I do not see another call to the other collection to populate the 'join'. So mongoose isn't even making the call.
@lostintranslation It should be model: 'Other' in that nested populate call.
@JohnnyHK to the rescue again, thanks! As a side note I though I might be able to get it all the first call Car.find().populate('partIds').populate({path: 'partIds.otherIds', model: 'Other').exec ... No luck guess you have to make the first query call to populate the partIds first.
Or, you can try the mongoose-deep-populate plugin and rewrite the entire thing with: Car.find().deepPopulate('partIds.otherIds').exec(...). (Disclaimer: I'm the author.)
|
29

Mongoose 4 support this

Car .find() .populate({ path: 'partIds', model: 'Part', populate: { path: 'otherIds', model: 'Other' } }) 

2 Comments

Note: model: 'Other' is necessary. Without it, it gives empty array. Docs doesn't specify it : mongoosejs.com/docs/populate.html#deep-populate
But I want to do double populate in one nested level. So basically something like below, Car .find() .populate({ path: 'partIds', model: 'Part', populate: { path: 'otherIds', model: 'Other' } populate: { path: 'ModelIds', model: 'Model' } })
4

Use mongoose deepPopulate plugin

car.find().deepPopulate('partIds.otherIds').exec(); 

Comments

0

It's should be better with

Car .find() .populate({ path: 'partIds.othersId' }) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.