-
Type: Bug
-
Resolution: Unresolved
-
Priority: Minor - P4
-
None
-
Affects Version/s: None
-
Component/s: None
-
Query Optimization
ElemMatchObjectMatchExpression is supposed to match arrays which have an object element satisfying the sub-predicates. However, there are some edge cases where it will match arrays which have an array element satisfying the sub-predicates. For example:
> db.foo.find() { "_id" : 0, "a" : [ [ ] ] } { "_id" : 1, "a" : [ [ { "b" : 1 } ] ] } { "_id" : 2, "a" : [ { "b" : 1 } ] } // Object $elemMatch with an empty object > db.foo.find({a: {$elemMatch: {}}}) { "_id" : 0, "a" : [ [ ] ] } { "_id" : 1, "a" : [ [ { "b" : 1 } ] ] } { "_id" : 2, "a" : [ { "b" : 1 } ] } // Somewhat surprisingly, this is also an object $elemMatch > db.foo.find({a: {$elemMatch: {$or: [{$alwaysTrue: 1}]}}}) { "_id" : 0, "a" : [ [ ] ] } { "_id" : 1, "a" : [ [ { "b" : 1 } ] ] } { "_id" : 2, "a" : [ { "b" : 1 } ] }
The hypothesis is that this is a mistake due to this line, which returns true for both objects and arrays.
The current behavior is consistent across all of our query frameworks. The proposal is to change the behavior for all query frameworks so that ElemMatchObjectMatchExpression only matches nested objects:
> db.foo.find({a: {$elemMatch: {}}}) { "_id" : 2, "a" : [ { "b" : 1 } ] } > db.foo.find({a: {$elemMatch: {$or: [{$alwaysTrue: 1}]}}}) { "_id" : 2, "a" : [ { "b" : 1 } ] }