Multiple populates - mongoosejs

Just a simple query, for example with a double ref in the model.

Schema / Model

var OrderSchema = new Schema({


user: {
type    : Schema.Types.ObjectId,
ref     : 'User',
required: true
},


meal: {
type    : Schema.Types.ObjectId,
ref     : 'Meal',
required: true
},
});


var OrderModel = db.model('Order', OrderSchema);

Query

OrderModel.find()
.populate('user') // works
.populate('meal') // dont works
.exec(function (err, results) {
// callback
});

I already tried something like

.populate('user meal')
.populate(['user', 'meal'])

In fact only one of the populates works.

So, how do is get two populates working ?

91448 次浏览

You're already using the correct syntax of:

OrderModel.find()
.populate('user')
.populate('meal')
.exec(function (err, results) {
// callback
});

Perhaps the meal ObjectId from the order isn't in the Meals collection?

UPDATE:
This solution remains for the version 3.x of Mongoose
http://mongoosejs.com/docs/3.8.x/docs/populate.html
but is no longer documented for >= 4.x versions of Mongoose and so the answer from @JohnnyHK is the only valid one for now on.

ORIGINAL POST
If you're using Mongoose >= 3.6, you can pass a space delimited string of the path names to populate:

OrderModel.find()
.populate('user meal')
.exec(function (err, results) {
// callback
});

http://mongoosejs.com/docs/populate.html

This has probably been resolved already, but this is my take on multiple & deep population in Mongodb > 3.6:

OrderModel.find().populate([{
path: 'user',
model: 'User'
}, {
path: 'meal',
model: 'Meal'
}]).exec(function(err, order) {
if(err) throw err;
if(order) {
// execute on order
console.log(order.user.username); // prints user's username
console.log(order.meal.value);    // you get the idea
}
});

There are probably other ways to do this, but this makes very readable code for beginners (like me)

i have same problem , but my mistake not in populate , i have an error in Model

if you do this

uncorrected

user: {
type: [Schema.Types.ObjectId],
ref: 'User'
}

correct

user: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]

you must put array around of object like this

You can try:

OrderModel.find()
.populate('user')
.populate('meal')
.exec(function (err, results) {
// callback
});

or with array options

OrderModel.find()
.populate([
{
path: "path1",
select: "field",
model: Model1
},
{
path: "path2",
select: "field2",
model: Model2
}
])
.exec(function (err, results) {
// callback
});

The best solution in my opinion is arrays when you are populating more than one foreign field on the same level. My code shows that I have multiple populates for different levels.

const patients = await Patient.find({})
.populate([{
path: 'files',
populate: {
path: 'authorizations',
model: 'Authorization'
},
populate: {
path: 'claims',
model: 'Claim',
options: {
sort: { startDate: 1 }
}
}
}, {
path: 'policies',
model: 'Policy',
populate: {
path: 'vobs',
populate: [{
path: 'benefits'
}, {
path: 'eligibility',
model: 'Eligibility'
}]
}
}]);

As you can see, wherever I needed more than one field of a document populated, I encased the populate key in an array and provided an array of objects, each object having a different path. Most robust and concise way to do it, in my opinion.

Latest mongoose v5.9.15 has ability to take array of populate fields so you can do,

.populate([ 'field1', 'field2' ])

To populate multiple fields with array of objects in controller/action function, model of both is already referred in schema of post

post.find({}).populate('user').populate('comments').exec(function (err,posts)
{
    

if(err)
{
console.log("error in post");
}
    

return  res.render('home',{
h1:"home Page",
posts:posts,
            

});
});

I think you are trying to the nested population you can visit official docs

User.
findOne({ name: 'Val' }).
populate({
path: 'friends',
// Get friends of friends - populate the 'friends' array for every friend
populate: { path: 'friends' }
});

In model file do something like:-

 doctorid:{
type:Schema.Types.ObjectId, ref:'doctor'
},
clinicid:{
type:Schema.Types.ObjectId, ref:'baseClinic'
}

In js file for adding operator use Something like:-

 const clinicObj = await BaseClinic.findOne({clinicId:req.body.clinicid})
const doctorObj = await Doctor.findOne({ doctorId : req.body.doctorid}) ;
**and add data as:-**
const newOperator = new Operator({
clinicid:clinicObj._id,
doctorid: doctorObj._id
});

Now, while populating

apiRoutes.post("/operator-by-id", async (req, res) => {
const id = req.body.id;
const isExist = await Operator.find({ _id: id }).populate(['doctorid','clinicid'])
if (isExist.length > 0) {
res.send(isExist)
} else {
res.send("No operator found");
}
});

You can use array syntax:

let results = await OrderModel.find().populate(['user', 'meal']);

You can also select which properties you want from each populate:

let results = await OrderModel.find().populate([{path: 'user', select: 'firstname'}, {path: 'meal', select: 'name'}]);