Search code examples
node.jsmongodbmongoosemongoose-populate

Mongoose querying data that needs populating


I have a Mongoose model that is pretty simple:

aclSchema = mongoose.Schema({
    _id: String,
    public_read: Boolean,
    public_write: Boolean,
});
aclModel = mongoose.model('acl', aclSchema);

And another model that references it:

thingSchema = mongoose.Schema({
    _id: String,
    _acl: { type: String, ref: 'acl' }
});
thingModel = mongoose.model('thing', thingSchema);

I need to be able to find documents ( thingModel ) where _acl.public_read is true. The problem i'm having is that since thing._acl is a ref, it's not populated until after the querying is done.

example:

thingModel.find({"_acl.public_read":true}).populate('_acl').exec(callback);

That returns no results because, I guess, _acl is a ref and it's not populated until after the find returns documents.

Just a side note, the schema's are more complicated than this and have other ref's in them that could be circular. I have not included them for simplicity sake, but the basic idea is there. If it was really this simple, i would use sub-documents and it would all work as expected.

Is there a better way to do this so I get the expected documents?


Solution

  • You can now do it in Mongo 3.2 using $lookup

    $lookup takes four arguments

    from: Specifies the collection in the same database to perform the join with. The from collection cannot be sharded.

    localField: Specifies the field from the documents input to the $lookup stage. $lookup performs an equality match on the localField to the foreignField from the documents of the from collection.

    foreignField: Specifies the field from the documents in the from collection.

    as: Specifies the name of the new array field to add to the input documents. The new array field contains the matching documents from the from collection.

    thingModel.aggregate([{
    
      $lookup: {
         from: 'aclCollection',
         localField: '_acl',
         foreignField: '_id',
         as : 'acl'
      },
      {$unwind: '$acl'},
      {$match:{"acl.public_read":true }}
    ], callback);
    

    In case of populate, it is not possible directly. Refer to similar question Mongoose nested query on Model by field of its referenced model