mongoose

Mongoose Population

Syntax#

  1. 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.


This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow