Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose Querying SubDocuments

Hello, im trying to query some nested documents at MongoDB. im using Mongoose.. my documents are like

[
{
    "_id": "5a2ca2227c42ad67682731d4",
    "description": "some descrition",
    "photos": [
        {
            "_id": "5a2ca22b7c42ad67682731d5",  
            "approved": false,
            "text":"good"  
        },
        {
            "_id": "5a2ca72b0a1aa173aaae07da",
            "approved": true,
            "text":"bad"
        },
        {
            "_id": "5a2cabf85a41077a2f87d4e3",    
            "approved": false,
            "text":"bad"
        }
    ]
}
]

I Want to find only photos that have the value "good", at text attribute, here is my find code:

ObjectSchema.find({
        'photos': {
            $elemMatch : {
                'text' : 'good'
            }
        }
    },function(err,result){
       console.log(result);
    });

I Wanted only to return the objct with the element with value that match my query, but when one object of this list match, the whole list of photos come with the result, not only who match the text.. How can i query it, and bring only the element who match, in this case, only the element which have "good" in text..

im using nodejs + mongoose

Thank you!

like image 427
Tobias Guimarães Avatar asked Dec 10 '17 04:12

Tobias Guimarães


People also ask

What is __ V in Mongodb?

Posted On: Jun 24, 2021. In Mongoose the “_v” field is the versionKey is a property set on each document when first created by Mongoose. This is a document inserted through the mongo shell in a collection and this key-value contains the internal revision of the document.

What is ref 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.


1 Answers

You are using find with only conditions, which will return entire documents. You can also specify a projection with find to include/exclude certain fields from documents. You can use the $elemMatch in the projection as follows:

ObjectSchema.find({
    'photos': {
        $elemMatch : {
            'text' : 'good'
        }
    }
}, {
    'photos': {
        $elemMatch : {
            'text' : 'good'
        }
    }
}, function(err,result){
   console.log(result);
});

But beware that $elemMatch in the projection will only include the first matching array element. That is probably not what you want based on the sample doc. Instead, you can use the Aggregation Framework. You can start with something like the following (untested) and shape the output as you prefer:

ObjectSchema.aggregate(
    {$unwind: "$photos"},
    {$match: {"photos.text": "good"}},
    function(err,result){
        console.log(result);
    }
)

where the $unwind makes a separate document for each element of the array.

To shape the output as you describe in the comment, you need to use a $group aggregation. Try adding the a $group aggregation similar to the following onto the end of pipeline:

{$group: {_id: "$_id", photos: {$push: "$photos"}}}
like image 98
logan rakai Avatar answered Sep 25 '22 19:09

logan rakai