Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mongoose conditional populate on subdocument

i have a schema that looks like this:

var UserSchema = new Schema({
  name              : { type: String, required: true },
  email             : { type: String, lowercase: true },
  fences            : [{type: Schema.Types.ObjectId, ref: 'Group'}]
});

var GroupMemberSchema = new Schema({ 
    user  : { type: Schema.Types.ObjectId, ref: 'User', required: true },
  status  : { type: String, default : 'Invited' }
});

var GroupSchema = new Schema({
  name          : String,
  members       : [GroupMemberSchema],
  type          : String
});

Group and User are exported as their own collections. I have an endpoint api/users/me in which I want to get my user and all my groups. Within the group I want to populate the users on my members. I have this working properly with this code:

User.findOne({
      _id: userId
    })
    .populate('groups')
    .exec(function(err, user) { 
      if (err) return next(err);
      if (!user) return res.json(401);

      var options = {
        path: 'groups.members.user',
        model: 'User'
      };

      User.populate(user, options, function (err, user) {
        return res.json(user);
      });

    });

However, I do not want to populate each member's associated user IF the group type == 'Special'. How would I put on the options do this?

like image 476
thebiglebowski11 Avatar asked Sep 01 '15 17:09

thebiglebowski11


People also ask

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.


2 Answers

You can use the "match" property inside populate.

Something like this:

User.findOne({
      _id: userId
    })
    .populate('groups')
    .exec(function(err, user) { 
      if (err) return next(err);
      if (!user) return res.json(401);

      var options = {
        path: 'groups.members.user',
        model: 'User',
        match: { 'group.type': { $ne: 'Special' } }
      };

      User.populate(user, options, function (err, user) {
        return res.json(user);
      });

    });
like image 82
Sulay Sumaria Avatar answered Nov 10 '22 09:11

Sulay Sumaria


You are populating subdocument, but it's no differences in populate mechanics

Just select all groups with type !== 'Special' and run populate on filtered array

var options = {
  path: 'members.user',
  model: 'User'
};
var specialGroups = _.filter(user.groups, function(group){return group.type !== 'Special'})

User.populate(specialGroups, options, function (err, user) {
  return res.json(user);
});

so inside groups array you have some documents populated and some not populated. It's strange, but you can use specialGroups instead of user.groups

like image 41
vmkcom Avatar answered Nov 10 '22 07:11

vmkcom