Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 842
Eric Xin Zhang Avatar asked Jun 08 '16 00:06

Eric Xin Zhang


People also ask

What does REF do in Mongoose schema?

The ref option is what tells Mongoose which model to use during population, in our case the Story model. All _id s we store here must be document _id s from the Story model. Note: ObjectId , Number , String , and Buffer are valid for use as refs.

How does populate work in Mongoose?

Mongoose Populate() Method. In MongoDB, Population is the process of replacing the specified path in the document of one collection with the actual document from the other collection.

What is execPopulate?

execPopulate is method on document, while . populate works on query object. Follow this answer to receive notifications.

What does Mongoose model return?

The mongoose. model() function of the mongoose module is used to create a collection of a particular database of MongoDB. The name of the collection created by the model function is always in plural format mean GFG to gfss and the created collection imposed a definite structure.


1 Answers

If you want to get a ProjectGroup object, which contains all the projects under that group. You can use Populate Virtuals. (Mongoose version > 4.5.0)

create a virtual schema in your schema file.

ProjectGroupSchema.virtual('projects', {
  ref: 'Project', // The model to use
  localField: 'projectGroupId', // Your local field, like a `FOREIGN KEY` in RDS
  foreignField: 'group', // Your foreign field which `localField` linked to. Like `REFERENCES` in RDS
  // If `justOne` is true, 'members' will be a single doc as opposed to
  // an array. `justOne` is false by default.
  justOne: false
});

and query in following:

ProjectGroup.find().populate('projects').exec(function(error, results) {
  /* `results.projects` is now an array of instances of `Project` */
});

If you cannot see virtuals part, plese set { toJSON: { virtuals: true } } to your model.

var ProjectGroupSchema = new Schema({
    projectGroupId    : String,
    title             : String
}, { toJSON: { virtuals: true } });
like image 88
Mangosteen Avatar answered Oct 25 '22 03:10

Mangosteen