Search code examples
node.jsmongoosemongoose-populate

Mongoose 'reversed' population, i.e. populating a parent object based on the reference defined in child schema


Let's borrow the excellent example from scaryguy with modification as below:

Project Group Schema:

var ProjectGroupSchema = new Schema({
    projectGroupId    : String,
    title             : String
});

Project Schema:

var ProjectSchema = new Schema({
    title         : {type : String, default : '', required : true},
    group         : {type: String, ref: 'ProjectGroup' },
    subscribers   : [{type: String, ref: 'User' }]
});

User Schema:

var UserSchema = new Schema({
    userId       : {type: String, require: true},
    firstName    : {type: String, required: true},
    lastName     : {type: String, required: true},
});

Then I can do following population:

project.findById(req.projectId})
 .populate('subscribers')
 .populate('group')
 .exec(function(err, project){
      console.log(project);
 });

Note that the reference fields are not Object IDs.

In this example the project schema has the reference fields to both the project group and subscribers which makes the above population possible.

What if I want to get a ProjectGroup object, which contains all the projects under that group, and each project contains its subscribers?

I'd say I'm looking for a 'reversed' population, i.e. populating a parent object based on the reference defined in child schema. At the moment I use async to query the ProjectGroup first, then query the projects based on the projectGroupId.

Thanks!


Solution

  • You can achieve this by using aggregate function. First group projects by "projectGroup" and then populate result.

    project.aggregate([
       {$group: {_id: "$group", projects: {$push: "$$ROOT"}}}
    ],
      function(err,results) {
        user.populate( results, { "path": "projects.subscribers" }, function(err,results) {
            if (err)
             console.log(err);
            res.send(results);
        });
    
    });