B T
B T

Reputation: 60935

Is there a way to prevent mongo queries "branching" on arrays?

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

Answers (2)

Sylvain Leroux
Sylvain Leroux

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

JohnnyHK
JohnnyHK

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

Related Questions