74

In Mongoose, I can use a query populate to populate additional fields after a query. I can also populate multiple paths, such as

Person.find({})
 .populate('books movie', 'title pages director')
 .exec()

However, this would generate a lookup on book gathering the fields for title, pages and director - and also a lookup on movie gathering the fields for title, pages and director as well. What I want is to get title and pages from books only, and director from movie. I could do something like this:

Person.find({})
 .populate('books', 'title pages')
 .populate('movie', 'director')
 .exec()

which gives me the expected result and queries.

But is there any way to have the behavior of the second snippet using a similar "single line" syntax like the first snippet? The reason for that, is that I want to programmatically determine the arguments for the populate function and feed it in. I cannot do that for multiple populate calls.

6 Answers 6

155

After looking into the sourcecode of mongoose, I solved this with:

var populateQuery = [{path:'books', select:'title pages'}, {path:'movie', select:'director'}];

Person.find({})
 .populate(populateQuery)
 .execPopulate()
Sign up to request clarification or add additional context in comments.

5 Comments

Does this kind of usage has any performance impacts against chaining multiple populates?
@GoncharDenys no, it fails with .populate(...).exec is not a function
execPopulate is not a function , please help
@AkosK @Anshuman Pattnaik just remove the .execPopulate() it will work properly
@scaryguy yes there are some impacts on performance :/ , but unfortunately there are some cases we are imposed to make multiple chaining populates... please if you have any suggestions let us know
17

you can also do something like below:

{path:'user',select:['key1','key2']}

Comments

5

You achieve that by simply passing object or array of objects to populate() method.

const query = [
    {
        path:'books', 
        select:'title pages'
    }, 
    {
        path:'movie', 
        select:'director'
    }
];
const result = await Person.find().populate(query).lean();

Consider that lean() method is optional, it just returns raw json rather than mongoose object and makes code execution a little bit faster! Don't forget to make your function (callback) async!

Comments

3
const order = await orderModel.findOne({ _id : id }).populate([
    {path : 'company_id' , select : ['companyName']} , 
    {path : 'customer_id' , select : ['first_name' , 'family_name' , 'email']}
]);

Comments

1

This is how it's done based on the Mongoose JS documentation http://mongoosejs.com/docs/populate.html

Let's say you have a BookCollection schema which contains users and books In order to perform a query and get all the BookCollections with its related users and books you would do this

models.BookCollection
    .find({})
    .populate('user')
    .populate('books')
    .lean()
    .exec(function (err, bookcollection) {
    if (err) return console.error(err);
    try {
        mongoose.connection.close();
        res.render('viewbookcollection', { content: bookcollection});

    } catch (e) {
        console.log("errror getting bookcollection"+e);
    }

2 Comments

They wanted to select certain data from each one of those paths. Like the book's path they only wanted to populate the title and pages. This would populate the whole model for users and books.
Its seems the author of the question solved it themselves anyways.
1

//Your Schema must include path

let createdData =Person.create(dataYouWant)


await createdData.populate([{path:'books', select:'title pages'},{path:'movie', select:'director'}])

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.