Reputation: 434
I have a mongodb collection (collection1) and I want to construct a mongodb query against it that meets the following conditions:
1) condition # 1
_field1 has to exist
2) condition # 2 (this is the trickier one)
Considering '_field2.drivers' is an array, we CAN'T have this combination:
(size of _fields2.drivers = 1) AND (_fields2.drivers.template = 'templateX')
Here is what I tried:
{
"collection1" :
{
$and:
[
{
'_field1':
{
$exists:true
}
}
{
$not:
{
$and:
[
{
'_field2.Drivers':
{
$size:1
}
}
{
'_field2.Drivers.template':"templateX"
}
]
}
}
]
}
}
It seems like in mongodb you can't use $not and $and together.
Also the premise "NOT (A AND C) is equivalent to NOT A OR NOT C" won't work for me.
How can I say NOT (A AND B) in mongo? I just can't have that combination (A AND B) together...
To Clarify
size of _field2.Drivers can be = 1 as long as _field2.Drivers.template is not = 'templateX'
and _field2.Drivers.template can be = 'templateX' as long as size of _fields2.Drivers is not = 1
Upvotes: 4
Views: 675
Reputation: 434
OK I found a slight problem with Neil's answer. It does not support the case where size of _field2.Drivers is not 1, and _field2.Drivers.template is not "templateX". We should accept this case as per the requirements. So the right answer would be:
{
"_field1": { "$exists": true },
"$or": [
{
"_field2.Drivers": { "$not": { "$size": 1 } }
},
{
"_field2.Drivers": { "$size": 1 },
"field2.Drivers.template": { "$ne": "templatex" }
}
]
}
Upvotes: 0
Reputation: 151132
ALL MongoDB query expression arguments are "already" an "AND" clause unless explicitly stated otherwise. So you "rarely" actually need to express $and
"explicitly" within a written query. There are few real cases, and most are actually suited to other query operators instead.
The combined logic of inclusive "AND" conditions therefore needs only one $not
assertion on $size
only, and the other negative can just be $ne
instead:
{
"_field1": { "$exists": true },
"_field2.Drivers": { "$not": { "$size": 1 } },
"field2.Drivers.template": { "$ne": "templatex" }
}
Unless of course you actually mean $or
for "either" condition:
{
"$or": [
{ "_field1": { "$exists": true } },
{
"_field2.Drivers": { "$not": { "$size": 1 } },
"field2.Drivers.template": { "$ne": "templatex" }
}
]
}
Or extend on the $or
:
{
"_field1": { "$exists": true },
"$or": [
{
"_field2.Drivers": { "$not": { "$size": 1 } },
"field2.Drivers.template": "templatex"
},
{
"_field2.Drivers": { "$size": 1 },
"field2.Drivers.template": { "$ne": "templatex" }
}
]
}
There is also a slightly "obtuse" usage of $nor
that applies here with a shorter syntax if not so clear a meaning:
{
"_field1": { "$exists": true },
"$nor": [
{
"_field2.Drivers": { "$size": 1 },
"field2.Drivers.template": "templatex"
}
]
}
Which with a single argument to $nor
is a syntactically "similar" to "NOT AND()
" as you are going to get.
Note: The fields "_field2"
and "field2"
are different here. You might actually mean to be referencing the same thing, in which case one is named incorrectly in your query.
Upvotes: 4