Reputation: 28530
If I run the following:
db.restaurants.find({'grades.grade': 'A'}, {'grades.grade':1})
Then I return all the documents that have a grade with an 'A'. That being, any document with at least one 'A' but there may be other grades. e.g:
{
"_id" : ObjectId("56c9a7038cc7f52917313091"),
"grades" : [
{
"grade" : "A"
},
{
"grade" : "B"
},
{
"grade" : "A"
},
{
"grade" : "A"
}
]
}
If I use the $ne
operator:
db.restaurants.find({'grades.grade': {$ne: 'A'}}, {'grades.grade':1})
Then I return all the documents that have all grades not equal to 'A'.
e.g.
{
"_id" : ObjectId("56c9a7038cc7f52917313245"),
"grades" : [
{
"grade" : "B"
},
{
"grade" : "B"
},
{
"grade" : "C"
},
{
"grade" : "B"
},
{
"grade" : "B"
}
]
}
Why does $ne
match all grades, but equal to match any grade?
NB: The same behaviour seems to be true in
$in
ans$nin
.$in
matches any document whereas$nin
matches all documents.NB2:
$not
exhibits the behaviour too.
Upvotes: 1
Views: 1689
Reputation: 486
This is a consequence of basic De Morgan logical negation.
NOT (A AND B) means (NOT A) OR (NOT B)
This can be directly translated to set theory, where disjunction (OR) means union and conjunction (AND) means intersection.
When you apply equals you're asking for ANY value that matches(disjunction). But when you negate that, you negate every single match as per De Morgan.
Upvotes: 0
Reputation: 5357
I understand your question, and I agree that from a functional perspective you are right: There should be a way to "negate" equals
in a way that is logically "give me anything that contains something that is not A
".
But I think the the way Mongo works here makes sense from a formal logic perspective. If you think about it logically, then the query db.restaurants.find({'grades.grade': 'A'})
returns
(grades[0].grade == 'A' || grades[1].grade == 'A' || grades[2].grade == 'A'|| grades[3].grade == 'A'...)
Basic formal logic says that the negation of the above statement is
(grades[0].grade != 'A' && grades[1].grade != 'A' && grades[2].grade != 'A'&& grades[3].grade != 'A'...)
Which is exactly what you got by using $ne
.
Upvotes: 1