Reputation: 3721
I have a collection
containing a list
of dicts
and I want to search if any dict contains two specific key:values
.
So for example I want to find_one
where a dict contains a specific first and last names. This is my collection:
{
"names": [
{
"firstName": "bob",
"lastName": "jones",
"age": "34",
"gender": "m"
},
{
"firstName": "alice",
"lastName": "smith",
"age": "56",
"gender": "f"
},
{
"firstName": "bob",
"lastName": "smith",
"age": "19",
"gender": "m"
},
]
}
I want to see if there is a record with bob smith as first and last names, I am searching this as:
first = 'bob'
last = 'smith'
nameExists = db.user.find_one({'$and':[{'names.firstName':first,'names.lastName':last}]})
Would this query retrieve the one record for bob smith?
Upvotes: 4
Views: 6860
Reputation: 151072
While it is mentioned that indeed the $and
operator is not required, in either form this is not the query that you want. Consider the following:
db.user.find_one({ 'names.firstName': 'alice','names.lastName': 'jones' })
This in fact does match the given record as there are both elements with "firstName" equal to "alice" and "lastName" values equal to "jones". But of course the problem here is simple in that there is no actual element in the array that has a sub-document for both of those values.
In order to match where an array element contains "both" the criteria given, you need to use the $elemMatch
operator. This applies the query condition to the "elements" of the array.
db.user.find_one({
'names': { '$elemMatch': { 'firstName': 'alice','lastName': 'smith' }
})
And of course if you tried "alice" and "jones" then that would not match as no element actually contains that operation.
Upvotes: 6
Reputation: 379
You don´t even need to add the $and parameter. In mongoDB, comma separated fields inside a query are joined by an implicit AND operator, so using simply {'names.firstName':first,'names.lastName':last} inside the find_one will work.
Anyway, that´s only a "clean code" fix; Your code will work properly as you are doing an "and" operation with just one element (note that the list used for the parameter $and contains only one dictionary).
Upvotes: 0
Reputation: 1085
Almost!
nameExists = db.user.find_one({'$and':[{'names.firstName':first},{'names.lastName':last}]})
You need to separate the asks into separate {} brackets.
Upvotes: 0