Spider
Spider

Reputation: 1470

Filter array in subdocument array field

I am trying to fetch an element from an array in the MongoDB. I think the aggregation filter is the right one to apply. But I tried million times already, I still cannot find where is the problem. Could you give me hand?

MongoDB sample data:

{
    "_id" : 12,
    "items" : [
            {
                    "columns" : [
                            {
                                    "title" : "hhh",
                                    "value" : 10
                            },
                            {
                                    "title" : "hahaha",
                                    "value" : 20
                            }
                    ]
            },
            {
                    "columns" : [
                            {
                                    "title" : "hiii",
                                    "value" : 50
                            }
                    ]
            }
    ]
}

My solution:

    db.myCollection.aggregate([
   {
      $project: {
         items: {
            $filter: {
               input: "$items",
               as: "item",
               cond: { $eq: [ "$$item.columns.title", "hahaha" ]}
            }
         }
      }
   }
]).pretty()

My result:

{
    "_id" : 15,
    "items" : [
            {
                    "columns" : [ ]
            },
            {
                    "columns" : [ ]
            }
    ]
}

Expected result:

{
    "_id" : 15,
    "items" : [
            {
                    "columns" : [
                            {
                                    "title" : "hahaha",
                                    "value" : 20
                            }
                    ]
            },
            {
                    "columns" : []
            }
    ]
}

I have checked the Mongo reference: https://docs.mongodb.com/manual/reference/operator/aggregation/filter/#example

MongoDB version:3.4.1
Testing environment: Mongo Shell

Upvotes: 3

Views: 3711

Answers (1)

Sede
Sede

Reputation: 61225

You need to use the $map array operator to $filter the sub array in your subdocument. Also you should do this in the $addFields aggregation pipeline stage to automatically include all others fields in the query result if you need them.

You can also replace the $addFields stage with $project as you were doing but in this case, you will need to explicitly include all other fields.

let value = "hahaha";

db.coll.aggregate([
    {
        "$addFields": { 
            "items": { 
                "$map": { 
                    "input": "$items", 
                    "as": "item", 
                    "in": { 
                        "columns": { 
                            "$filter": { 
                                "input": "$$item.columns", 
                                "as": "elt", 
                                "cond": { "$eq": [ "$$elt.title", value ] } 
                            } 
                        }
                    }
                } 
            } 
        } 
    } 
])

Upvotes: 7

Related Questions