Home > Net >  MongoDB -- Filter if all objects in array matches another array
MongoDB -- Filter if all objects in array matches another array

Time:07-13

Given documents like the one below, I'd like to return _id only if all elements of the input_array matches the list of available objects. For these examples, the first object should match while the second does not because key3 in first element is "P" instead of "c" and key2 for second element cannot be found in the second lookup object.

{
    _id: ObjectId('abcd1234001'),
    input_array: [
        {
            "key1": "a",
            "key2": "b",
        },
        {
            "key1": "x"
        }
    ]
},
{
    _id: ObjectId('abcd1234002'),
    input_array: [
        {
            "key1": "a",
            "key2": "b",
            "key3": "P",
        },
        {
            "key1": "x",
            "key2": "y",
        }
    ]
}

list of available objects are:

[
   {
      "key1": "a",
      "key2": "b",
      "key3": "c",
   },
   {
      "key1": "x"
   }
]

CodePudding user response:

Definitely not the best looking query, but the idea is to iterate over every item in the input array and try to find an element that matches it, if every single element matches this filter then the document will be matched, like so:

(notice i changed the input structure, this is just for connivence of the query, you can do it yourself in code or in mongo )

const input = [
   ["a", "b", "c"],
   ["x"]
];

db.collection.aggregate([
  {
    $match: {
      $expr: {
        $eq: [
          {
            $size: "$input_array"
          },
          {
            $size: {
              $filter: {
                input: {
                  $map: {
                    input: "$input_array",
                    as: "outer",
                    in: {
                      $map: {
                        input: {
                          "$objectToArray": "$$outer"
                        },
                        in: "$$this.v"
                      }
                    }
                  }
                },
                as: "outer",
                cond: {
                  $gt: [
                    {
                      $size: {
                        $filter: {
                          input: input,
                          cond: {
                            $eq: [
                              {
                                $size: {
                                  "$setDifference": [
                                    "$$outer",
                                    "$$this"
                                  ]
                                }
                              },
                              0
                            ]
                          }
                        }
                      }
                    },
                    0
                  ]
                }
              }
            }
          }
        ]
      }
    }
  }
])

Mongo Playground

CodePudding user response:

If the array is fixed to 2 elements, try this. I convert data in each element to array by $objectToArray and combine it by $concatArrays and matched by $setIsSubset.

const listof = [{ "key1": "a", "key2": "b", "key3": "c", }, { "key1": "x" }];

db.collection.aggregate([
    {
        $match: {
            $expr: {
                $eq: [
                    {
                        $setIsSubset: [
                            {
                                $concatArrays: [
                                    { $objectToArray: { $arrayElemAt: ['$input_array', 0] } },
                                    { $objectToArray: { $arrayElemAt: ['$input_array', 1] } }
                                ]
                            },{
                                $concatArrays: [
                                    { $objectToArray: { $arrayElemAt: [listof, 0] } },
                                    { $objectToArray: { $arrayElemAt: [listof, 1] } }
                                ]
                            }
                        ]
                    }
                    , true]
            }
        }
    }
])
  • Related