2

I have following data.

[
  {
    "_id": 1,
    "array": [
      {
        "name": "name1",
        "nestedArray": [
          {
            "key": "key1",
            "value": "value1"
          },
          {
            "key": "key2",
            "value": "value2"
          }
        ]
      },
      {
        "name": "name2",
        "nestedArray": [
          {
            "key": "key1",
            "value": "abc"
          },
          {
            "key": "key2",
            "value": "value2"
          }
        ]
      }
    ]
  }
]

playground I want to keep the entry whose nestedArray contains 2 matching elements and remove others. The 2 elements are below

{
    "key": "key1",
    "value": "abc"
},
{
    "key": "key2",
    "value": "value2"
}

So that the result will be below

[
  {
    "_id": 1,
    "array": [
      {
        "name": "name2",
        "nestedArray": [
          {
            "key": "key1",
            "value": "abc"
          },
          {
            "key": "key2",
            "value": "value2"
          }
        ]
      }
    ]
  }
]

The one whose name="name1" is removed since it has only one matching element. Feels like we could use $elemMatch but couldn't figure it out.

7
  • 1
    Can you please elaborate, the filter you want to apply? Commented May 6, 2021 at 3:19
  • 1
    How do you decide key1 should be "abc" and not "value1"? Commented May 6, 2021 at 3:36
  • @Joe You see there are two documents in nestedArray, only the one with matches both documents should stay. So the first document in array should be removed. Commented May 6, 2021 at 3:48
  • 1
    That's what I don't understand, one document has "abc" and the other "value1", so that doesn't match. I'm just not seeing the logic. Commented May 6, 2021 at 3:52
  • @CharchitKapoor you see there are two elements in array. I want to keep only the element whose nestedArray have two matching elements. Commented May 6, 2021 at 3:55

2 Answers 2

1

First, Unwind the array so that you can easily access the nestedArray .

Second, use $all and $elementMatch on nestedArray

db.collection.aggregate([
  {
    $unwind: "$array"
  },
  {
    $match: {
      "array.nestedArray": {
        $all: [
          {
            "$elemMatch": {
              key: "key1",
              value: "abc"
            }
          },
          {
            "$elemMatch": {
              key: "key2",
              value: "value2"
            }
          }
        ]
      }
    }
  },
  {
    $group: {
      _id: "$_id",
      array: {
        "$push": "$array"
      }
    }
  }
])

playground

Sign up to request clarification or add additional context in comments.

Comments

0

You didn't really specify how you input looks but the strategy will stay the same regardless, We will iterate over the array with $filter and match only documents that their subarray's size is equal to a filtered subarray based on the given input, like so:

// the current input structure.
inputArray = [
    {
        "key": "key1",
        "value": "abc"
    },
    {
        "key": "key2",
        "value": "value2"
    }
];
db.collection.aggregate([
  {
    $project: {
      array: {
        $filter: {
          input: "$array",
          as: "element",
          cond: {
            $and: [
              {
                $eq: [
                  {
                    $size: {
                      $filter: {
                        input: "$$element.nestedArray",
                        as: "nested",
                        cond: {
                          "$setIsSubset": [
                            [
                              "$$nested"
                            ],
                            inputArray
                          ]
                        }
                      }
                    },
                    
                  },
                  {
                    $size: "$$element.nestedArray"
                  }
                ]
              },
              {  // this is required for an exact match otherwise subsets are possible, if you wan't to allow it delete this equality completly.
                $eq: [
                  {
                    $size: "$$element.nestedArray"
                  },
                  {
                    $size: inputArray
                  }
                ]
              }
            ]
          }
        }
      }
    }
  }
])

Again if the input is coming in a different structure you'll have to change the $eq conditions

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.