MongoDb - $match filter not working in subdocument

This is Collection Structure

[{
   "_id"              : "....",
   "name"             : "aaaa",
   "level_max_leaves" : [
                           {
                              level      : "ObjectIdString 1",
                              max_leaves : 4,
                           }
                        ]
},
{
   "_id"              : "....",
   "name"             : "bbbb",
   "level_max_leaves" : [
                           {
                              level      : "ObjectIdString 2",
                              max_leaves : 2,
                           }
                        ]
}]

I need to find the subdocument value of level_max_leaves.level filter when its matching with given input value.

And this how I tried,

For example,

var empLevelId = 'ObjectIdString 1' ;

MyModel.aggregate(
    {$unwind: "$level_max_leaves"},
    {$match: {"$level_max_leaves.level": empLevelId } },
    {$group: { "_id": "$level_max_leaves.level", 
               "total": { "$sum": "$level_max_leaves.max_leaves" }}},
    function (err, res) {
        console.log(res);
});

But here the $match filter is not working. I can't find out exact results of ObjectIdString 1

If I filter with name field, its working fine. like this,

{$match: {"$name": "aaaa" } },

But in subdocument level its returns 0.

{$match: {"$level_max_leaves.level": "ObjectIdString 1"} },

My expected result was,

{
   "_id"              : "ObjectIdString 1",
   "total"            : 4,
}

You have typed the $match incorrectly. Fields with $ prefixes are either for the implemented operators or for "variable" references to field content. So you just type the field name:

MyModel.aggregate(
    [
        { "$match": { "level_max_leaves.level": "ObjectIdString 1" } },
        { "$unwind": "$level_max_leaves" },
        { "$match": { "level_max_leaves.level": "ObjectIdString 1" } },
        { "$group": { 
            "_id": "$level_max_leaves.level", 
           "total": { "$sum": "$level_max_leaves.max_leaves" }
        }}
    ],
    function (err, res) {
        console.log(res); 
    }
);

Which on the sample you provide produces:

{ "_id" : "ObjectIdString 1", "total" : 4 }

It is also good practice to $match first in your pipeline. That is in fact the only time an index can be used. But not only for that, as without the initial $match statement, your aggregation pipeline would perform an $unwind operation on every document in the collection, whether it met the conditions or not.

So generally what you want to do here is

  1. Match the documents that contain the required elements in the array
  2. Unwind the array of the matching documents
  3. Match the required array content excluding all others