MongoDB aggregation use $elemMatch for nested array

Viewed 597

I try to learn aggregation concept in MongoDB. I create an object like this for training.

"_id": "601c4bb56e018211b02abbf8",   
"isDeleted": false,
"name": "TeacherName1",
"class": "7",
"students": [
     { "_id": "601c4bb56e018211b02abbf9", isDeleted:true,  "name": "student-1", "studentGroup": "A",   "avgResult": 36},
     { "_id": "601c4bb56e018211b02abbfa", isDeleted:false, "name": "student-2", "studentGroup": "A",   "avgResult": 55},
     { "_id": "601c4bb56e018211b02abbfb", isDeleted:false, "name": "student-3", "studentGroup": "B",   "avgResult": 44.66},
     { "_id": "601c4bb56e018211b02abbfc", isDeleted:false, "name": "student-4", "studentGroup": "C",   "avgResult": 83.66},
     { "_id": "601c4bb56e018211b02abbfd", isDeleted:true,  "name": "student-5", "studentGroup": "B",   "avgResult": 37},
     { "_id": "601c4bb56e018211b02abbfe", isDeleted:true,  "name": "student-6", "studentGroup": "C",   "avgResult": 39.66},
]

I want to get teacher information and deleted students (isDeleted=true). So I try to get this result.

    "_id": "601c4bb56e018211b02abbf8",   
    "isDeleted": false,
    "name": "TeacherName1",
    "class": "7",
    "students": [
         { "_id": "601c4bb56e018211b02abbf9", isDeleted:true,  ...},
         { "_id": "601c4bb56e018211b02abbfd", isDeleted:true, ...},
         { "_id": "601c4bb56e018211b02abbfe", isDeleted:true,  ...},
    ]

I get result with use $unwind and $filter. But can I get this result with only $elemMatch?

If I use this query

 this.aggregate([
    {
      $match: {
        _id: mongoose.Types.ObjectId("601c4bb56e018211b02abbf8"),
        isDeleted: false,
        "students.isDeleted":true
      },
    },
  ]);

It returns all object.

If I try this

this.aggregate([
    {
      $match: {
        _id: mongoose.Types.ObjectId("601c4bb56e018211b02abbf8"),
        isDeleted: false,
        students:{
            $elemMatch:{
                isDeleted:true
            }
        }
      },
    },
  ]);

It returns all object.

1 Answers

$match will just give you the whole doc should you match however you may use $project with $filter using another stage

given

db.dummy.insert({studs:[{isDeleted:true, name:'a'},{isDeleted: true, name:'b'},{name:'c'}]})
db.dummy.insert({studs:[{name:'c'}]})
> match = {$match:{studs:{$elemMatch: {isDeleted:true}}}}
> project = {$project: { deletedStuds: {$filter:{input: '$studs', as:'stud', cond:{ $eq: ['$$stud.isDeleted', true]} } } }}
{
  "$project" : {
    "deletedStuds" : {
      "$filter" : {
        "input" : "$studs",
        "as" : "stud",
        "cond" : {
          "$eq" : [
            "$$stud.isDeleted",
            true
          ]
        }
      }
    }
  }
}

> db.dummy.aggregate(match, project)
{ "_id" : ObjectId("6020351eb965951ac8a1eb62"), "deletedStuds" : [ { "isDeleted" : true, "name" : "a" }, { "isDeleted" : true, "name" : "b" } ] }

Related