I am writing an aggregation pipeline, that will essentially have docs like this:
{
obj1: {foo: 'bar'},
obj2: {foo: 'baar'}
}
Can I somehow write a query to get all the documents, where obj1 and obj2 don’t match?
I tried with the $eq
, but this operator does not seem to work.
NeNaD
(Nenad Milosavljevic)
June 9, 2022, 10:51am
2
Does both obj1
and obj2
have only the foo
as sub-property? Do you want to try to match only foo
sub-property or all sub-properties in case of multiple sub-properties?
The foo
sub-property was only to make the example easy
My objective is to test all sub-properties.
I just found out that $eq
actually works, but the order of keys inside an object is important!
I’m investigating my options…
NeNaD
(Nenad Milosavljevic)
June 9, 2022, 11:07am
4
Here is how you can do it:
$objectToArray
- to convert objects to arrays
$setEquals
- to compare arrays
db.collection.aggregate([
{
"$match": {
"$expr": {
"$setEquals": [
{
"$objectToArray": "$object_1"
},
{
"$objectToArray": "$object_2"
}
]
}
}
}
])
Working example
Use case when one or both sub-properties are not of type “object”
Here is the updated answer that would also work if one or both sub-properties are not of type object
:
$type
- to check if both sub-properties are of the type `object.
If they are, do the comparation with $setEquals
and objectToArray
.
If they are not, do the comparation with $eq
operator.
db.collection.aggregate([
{
"$match": {
"$expr": {
"$cond": {
if: {
"$and": [
{
"$eq": [
{
"$type": "$object_1"
},
"object"
]
},
{
"$eq": [
{
"$type": "$object_2"
},
"object"
]
}
]
},
then: {
"$setEquals": [
{
"$objectToArray": "$object_1"
},
{
"$objectToArray": "$object_2"
}
]
},
else: {
"$eq": [
"$object_1",
"$object_2"
]
}
}
}
}
}
])
Working Example
4 Likes
Thanks - it actually works
Hi @NeNaD
We are starting to see some issues when comparing complex objects, with nested arrays and objects. Is $objectToArray
capable of working with nested objects - or is there some work-around?
NeNaD
(Nenad Milosavljevic)
June 13, 2022, 12:13pm
7
Hi @Alex_Bjorlig ,
I am not sure. Can you add example documents?
If you have nested objects, maybe after $objectToArray
it will have the same issue as when you just try to match 2 objects and keys are not in the same order.
Issues seem to arrive when the 2 objects to compare looks like this:
{
objectToCompare: {
"foo": "bar",
"fooLevels": {
"1": "level 1",
"2": "level 2",
"3": "level 3"
}
}
}
But it actually seems like I can get it “to work” if I project fooLevels
directly
NeNaD
(Nenad Milosavljevic)
June 13, 2022, 12:42pm
9
It does not work because in this case foo
is not an object, it’s a string. And $objectToArray
throws an error because it expects input of type object.
I’m sorry for not being explicit about the data structure. I updated the example…
NeNaD
(Nenad Milosavljevic)
June 14, 2022, 10:06pm
11
Hi,
I updated my answer. Can you check it?