Mongoose Population
Syntax#
- Model.Query.populate(path, [select], [model], [match], [options]);
Parameters#
Param | Details |
---|---|
path | String - The field key to be populated |
select | Object, String - Field selection for the population query. |
model | Model - Instance of the referenced model |
match | Object - Populate conditions |
options | Object - Query options |
## Simple Populate | |
Mongoose populate is used to show data for referenced documents from other collections. |
Lets say we have a Person
model that has referenced documents called Address
.
Person Model
var Person = mongoose.model('Person', {
fname: String,
mname: String,
lname: String,
address: {type: Schema.Types.ObjectId, ref: 'Address'}
});
Address Model
var Address = mongoose.model('Address', {
houseNum: String,
street: String,
city: String,
state: String,
country: String
});
To populate Address
inside Person
using it’s ObjectId, using let’s say findOne()
, use the populate()
function and add the field key address
as the first parameter.
Person.findOne({_id: req.params.id})
.populate('address') // <- use the populate() function
.exec(function(err, person) {
// do something.
// variable `person` contains the final populated data
});
Or
Person.findOne({_id: req.params.id}, function(err, person) {
// do something
// variable `person` contains the final populated data
})
.populate('address');
The query above should produce the document below.
Person Doc
{
"_id":"123abc",
"fname":"John",
"mname":"Kennedy",
"lname":"Doe",
"address":"456def" // <- Address' Id
}
Address Doc
{
"_id":"456def",
"houseNum":"2",
"street":"Street 2",
"city":"City of the dead",
"state":"AB",
"country:"PH"
}
Populated Doc
{
"_id":"123abc",
"fname":"John",
"mname":"Kennedy",
"lname":"Doe",
"address":{
"_id":"456def",
"houseNum":"2",
"street":"Street 2",
"city":"City of the dead",
"state":"AB",
"country:"PH"
}
}
Neglect a few fields
Let’s say you don’t want the fields houseNum
and street
in the address
field of the final populated doc, use the populate()
as follows,
Person.findOne({_id: req.params.id})
.populate('address', '-houseNum -street') // note the `-` symbol
.exec(function(err, person) {
// do something.
// variable `person` contains the final populated data
});
Or
Person.findOne({_id: req.params.id}, function(err, person) {
// do something
// variable `person` contains the final populated data
})
.populate('address', '-houseNum -street'); // note the `-` symbol
This will produce the following final populated doc,
Populated Doc
{
"_id":"123abc",
"fname":"John",
"mname":"Kennedy",
"lname":"Doe",
"address":{
"_id":"456def",
"city":"City of the dead",
"state":"AB",
"country:"PH"
}
}
Populate only a few fields
If you only want the fields houseNum
and street
in the address
field in the final populated doc, use the populate()
function as follows in the above two methods,
Person.findOne({_id: req.params.id})
.populate('address', 'houseNum street')
.exec(function(err, person) {
// do something.
// variable `person` contains the final populated data
});
Or
Person.findOne({_id: req.params.id}, function(err, person) {
// do something
// variable `person` contains the final populated data
})
.populate('address', 'houseNum street');
This will produce the following final populated doc,
Populated Doc
{
"_id":"123abc",
"fname":"John",
"mname":"Kennedy",
"lname":"Doe",
"address":{
"_id":"456def",
"houseNum":"2",
"street":"Street 2"
}
}
Nested Population
Lets say you have a user
schema, which contains name
, contactNo
, address
, and friends
.
var UserSchema = new mongoose.Schema({
name : String,
contactNo : Number,
address : String,
friends :[{
type: mongoose.Schema.Types.ObjectId,
ref : User
}]
});
If you want to find a user, his friends and friends of friends, you need to do population on 2 levels i.e. nested Population.
To find friends and friends of friends:
User.find({_id : userID})
.populate({
path : 'friends',
populate : { path : 'friends'}//to find friends of friends
});
All the parameters
and options
of populate
can be used inside nested populate too, to get the desired result.
Similarly, you can populate
more levels
according to your requirement.
It is not recommended to do nested population for more than 3 levels. In case you need to do nested populate for more than 3 levels, you might need to restructure your schema.