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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.