-
Type:
Improvement
-
Resolution: Done
-
Priority:
Minor - P4
-
None
-
Affects Version/s: None
-
Component/s: Index Maintenance, Querying
-
None
-
None
-
3
-
None
-
None
-
None
-
None
-
None
-
None
Given the example of a set of documents like this:
{ "status" : "A", "type" : "C" } { "status" : "A", "type" : "D" } { "status" : "B", "type" : "C" } { "status" : "B", "type" : "D" }
Currently if you wanted to find all documents that did not contain the combination of "status": "A" and "type": "C" you would have to resort to JavaScript evaluation.
db.collection.find(function() { !( this.status == "A" && this.type == "C") })
The aggregation pipeline allows such casting to a projection of a field:
db.collection.aggregate([ { "$project": { "status": 1, "type": 1, "unmatched": { "$not": { "$and": [ { "$eq": [ "$status", "A" ] }, { "$eq": [ "$type", "C" ] } ] } } }}, { "$match": { "unmatched": false }} ]) {code:javascript} But as there is not a native form of this for a query you could not filter for a $match stage. The seemingly natural form would be the similar: {code: javascript} db.collection.find({ "$not": { "status": "A", "type": "C" } })
Where the existing $not operator applied it's left side evaluation to the query match negating the whole expression of the query on the right side.
Not sure if there is an efficient way to apply this to index values or whether the result would be the same collection scan for all documents not matching the exclusion.
The general problem presently being that $not is not allowed as a top level operator here at the moment and cannot reverse the entire query condition as it expects a left side field value. And the JavaScript form for a $where clause is not allowed within an aggregation expression
error: { "$err" : "Can't canonicalize query: BadValue unknown top level operator: $not", "code" : 17287 }