Multiple populates - mongoosejs
Javascriptnode.jsMongodbMongooseJavascript Problem Overview
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 ?
Javascript Solutions
Solution 1 - Javascript
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?
Solution 2 - Javascript
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
});
Solution 3 - Javascript
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)
Solution 4 - Javascript
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.
Solution 5 - Javascript
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'}]);
Solution 6 - Javascript
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
});
Solution 7 - Javascript
Latest mongoose v5.9.15
has ability to take array of populate fields
so you can do,
.populate([ 'field1', 'field2' ])
Solution 8 - Javascript
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");
}
});
Solution 9 - Javascript
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
Solution 10 - Javascript
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,
});
});
Solution 11 - Javascript
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' }
});