MongoDB/PyMongo: Querying multiple criteria - unexpected results
Asked Answered
B

2

14

I have a collection where some of the objects feature an key foo. I now try to query for all objects that indeed have this key but not with the specific value bar. For this I use the following query:

collection.find({'foo': {'$exists': True}, 'foo': {'$ne': 'bar'}})

I thought that both criteria are connected via a logical AND. However, I get also objects that don't feature key foo. In fact, I get the same result when I just use the query

collection.find({'foo': {'$ne': 'bar'}})

On the other hans, if I use

collection.find({'foo': {'$exists': True}})

I correctly only get objects with foo but obvisouly all of them, so some of them have the value bar.

How do I have to formulate my query to achieve my initial result? Is there a kind of order in which multiple criteria are tested? Do I explicitly specify the logical AND of both criteria?

Basle answered 10/5, 2014 at 4:43 Comment(2)
This is a great example of a basic pymongo query. I wish it came up earlier when I googled "pymongo find examples" :-\ . +13d
I don't think there's need for specific examples for PyMongo since the syntax is essentially the same as when using the Mongo shell. I think the Mongo shell is a bit more generous when it comes to having quotes around keywords and field names(e.g., {$ne : 'bar'} should work as well as {'$ne' : 'bar'}). Maybe the capitalization of, e.g., True might matter also.Basle
B
42

You can use $and to join multiple conditions:

collection.find({"$and": [{"foo": {'$ne': 'bar'}}, 
                          {"foo": {'$exists': True}}]})
Birnbaum answered 10/5, 2014 at 4:57 Comment(2)
Perfect, thanks! I just thought that if you have a list of criteria, AND is the implicitly given way to test them. Most example I found focused only on $or, hence perhaps my misconception. But to support arbitrary complex conditions, and $and is of course very meaningful.Basle
shorter version for general uses {"$and": [{"key1": value1}, {"key2": value2}]}Dian
M
20

No necessary to use $and, it also works

db.collection.find({"foo":{"$ne":"bar", "$exists":true}})
Mastigophoran answered 10/5, 2014 at 5:24 Comment(2)
Cool, thanks! So I guess I have this issue since both criterea refer to the same key foo. Is there any difference regarding the performance between both solutions?Basle
making use of "$and" will return the entire document (say it returns just one result), whereas querying without "$and" will return only the resulting document id .Normy

© 2022 - 2024 — McMap. All rights reserved.