Reputation: 60935
If I have the following documents:
{a: {x:1}} // without array
{a: [{x:1}]} // with array
Is there a way to query for {'a.x':1}
that will return the first one but not the second one? IE, I want the document where a.x is 1, and a is not an array.
Upvotes: 5
Views: 85
Reputation: 52030
Please note that future version of MongoDB would incorporate the $isArray
aggregation expression. In the meantime...
...the following code will do the trick as the $elemMatch
operator matches only documents having an array field:
> db.test.find({"a.x": 1, "a": {$not: {$elemMatch: {x:1}}}})
Given that dataset:
> db.test.find({},{_id:0})
{ "a" : { "x" : 1 } }
{ "a" : [ { "x" : 1 } ] }
{ "a" : [ { "x" : 0 }, { "x" : 1 } ]
It will return:
> db.test.find({"a.x": 1, "a": {$not: {$elemMatch: {x:1}}}}, {_id:0})
{ "a" : { "x" : 1 } }
Please note this should be considered as a short term solution. The MongoDB team took great cares to ensure that [{x:1}]
and {x:1}
behave the same (see dot-notation or $type
for arrays). So you should consider that at some point in the future, $elemMatch
might be updated (see JIRA issue SERVER-6050). In the meantime, maybe worth considering fixing your data model so it would no longer be necessary to distinguish between an array containing one subdocument and a bare subdocument.
Upvotes: 5
Reputation: 312035
You can do this by adding a second term that ensures a
has no elements. That second term will always be true when a
is a plain subdoc, and always false when a
is an array (as otherwise the first term wouldn't have matched).
db.test.find({'a.x': 1, 'a.0': {$exists: false}})
Upvotes: 5