harryk
harryk

Reputation: 153

MongoDB how to filter in nested array

I have below data. I want to find value=v2 (remove others value which not equals to v2) in the inner array which belongs to name=name2. How to write aggregation for this? The hard part for me is filtering the nestedArray which only belongs to name=name2.

{
  "_id": 1,
  "array": [
    {
      "name": "name1",
      "nestedArray": [
        {
          "value": "v1"
        },
        {
          "value": "v2"
        }
      ]
    },
    {
      "name": "name2",
      "nestedArray": [
        {
          "value": "v1"
        },
        {
          "value": "v2"
        }
      ]
    }
  ]
}

And the desired output is below. Please note the value=v1 remains under name=name1 while value=v1 under name=name2 is removed.

{
  "_id": 1,
  "array": [
    {
      "name": "name1",
      "nestedArray": [
        {
          "value": "v1"
        },
        {
          "value": "v2"
        }
      ]
    },
    {
      "name": "name2",
      "nestedArray": [
        {
          "value": "v2"
        }
      ]
    }
  ]
}

Upvotes: 3

Views: 1616

Answers (2)

Tiya Jose
Tiya Jose

Reputation: 1419

You can use the following aggregation query:

db.collection.aggregate([
  {
    $project: {
      "array": {
        "$concatArrays": [
          {
            "$filter": {
              "input": "$array",
              "as": "array",
              "cond": {
                "$ne": [
                  "$$array.name",
                  "name2"
                ]
              }
            }
          },
          {
            "$filter": {
              "input": {
                "$map": {
                  "input": "$array",
                  "as": "array",
                  "in": {
                    "name": "$$array.name",
                    "nestedArray": {
                      "$filter": {
                        "input": "$$array.nestedArray",
                        "as": "nestedArray",
                        "cond": {
                          "$eq": [
                            "$$nestedArray.value",
                            "v2"
                          ]
                        }
                      }
                    }
                  }
                }
              },
              "as": "array",
              "cond": {
                "$eq": [
                  "$$array.name",
                  "name2"
                ]
              }
            }
          }
        ]
      }
    }
  }
])

MongoDB Playground

Upvotes: 1

turivishal
turivishal

Reputation: 36094

You can try,

  • $set to update array field, $map to iterate loop of array field, check condition if name is name2 then $filter to get matching value v2 documents from nestedArray field and $mergeObject merge objects with available objects
let name = "name2", value = "v2";
db.collection.aggregate([
  {
    $set: {
      array: {
        $map: {
          input: "$array",
          in: {
            $mergeObjects: [
              "$$this",
              {
                $cond: [
                  { $eq: ["$$this.name", name] }, //name add here
                  {
                    nestedArray: {
                      $filter: {
                        input: "$$this.nestedArray",
                        cond: { $eq: ["$$this.value", value] } //value add here
                      }
                    }
                  },
                  {}
                ]
              }
            ]
          }
        }
      }
    }
  }
])

Playground

Upvotes: 1

Related Questions