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
]
}
}
}
}
]
}
}
}
])
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]
}
}
}
])