jeem
jeem

Reputation: 919

How do I find a mongodb document where no embedded document or array element matches conditions?

Given this:

{ _id: 1, results: [ {a: 82, b: 81}, {a: 82, b: 88} ] }
{ _id: 2, results: [ {a: 82, b: 90}, {a: 82, b: 33} ] }

I want to find the docs which have no results with a or b less than 80. (doc 1 in this case) I know I could use $elemMatch to find the docs with any result containing an a or b less than 80. Is there a way to do the reverse?

Alternatively, I could rewrite my conditions to find docs where all results have a and b greater than 79. Is there an operator which does that?

Upvotes: 1

Views: 75

Answers (2)

vladzam
vladzam

Reputation: 5908

Yes, the opposite of $lt is $gt, which returns all documents that have a certain attribute greater than the specified value.

db.collection.find({results: {$elemMatch: { $and: [{a: {$gt: 79}}, {b: {$gt: 79}}]}}});

EDIT: I have further investigated and it appears that $elemMatch only checks the first element of the array. I have also checked the solution provided by wdberkeley and it works just as intended. Apart from the query built by wdberkeley, the only alternative would be to use the aggregation framework, but that would be far more complex than a simple find query.

Upvotes: 0

wdberkeley
wdberkeley

Reputation: 11671

Use $not and $or:

db.test.find({ "results" : { 
    "$not" : { 
        "$elemMatch" : { 
            "$or" : [
                { "a" : { "$lt" : 80 } }, 
                { "b" : { "$lt" : 80 } } 
             ]
         } 
     } 
} })

The negation of your condition is "documents with some result having a or b values less than 80". I wrote a query for that, and negated it. Given the way queries work on array elements, I believe it is generally necessary to use $not to enforce a condition on every array element.

Upvotes: 2

Related Questions