user641887
user641887

Reputation: 1586

mongodb find elements in Array

I am playing around with mongodb and having troubles with finding elements in an array

My collection looks like this

{
        "_id" : ObjectId("4c4b1476238d3b4dd5000002"),
        "username" : "pbakkum",
        "first_name" : "Peter",
        "last_name" : "Bakkum",
        "age" : 21,
        "addresses" : [
                {
                        "name" : "home",
                        "street" : "588 5th Street",
                        "city" : "Brooklyn",
                        "state" : "CA",
                        "zip" : 11215
                },
                {
                        "name" : "work",
                        "street" : "588 5th Street",
                        "city" : "Brooklyn",
                        "state" : "CA",
                        "zip" : 11215
                },
                {

                }
        ]
}
{
        "_id" : ObjectId("4c4b1476238d3b4dd5000001"),
        "username" : "kbanker",
        "email" : "[email protected]",
        "first_name" : "Kyle",
        "last_name" : "Banker",
        "hashed_password" : "bd1cfa194c3a603e7186780824b04419",
        "addresses" : [
                {
                        "name" : "home",
                        "street" : "588 5th Street",
                        "city" : "Brooklyn",
                        "state" : "NY",
                        "zip" : 11215
                },
                {
                        "name" : "work",
                        "street" : "1 E. 23rd Street",
                        "city" : "New York",
                        "state" : "NY",
                        "zip" : 10010
                }
        ],
        "payment_methods" : [
                {
                        "name" : "VISA",
                        "last_four" : 2127,
                        "crypted_number" : "43f6ba1dfda6b8106dc7",
                        "expiration_date" : ISODate("2016-05-01T07:00:00Z")
                }
        ],
        "age" : 151
}

When I fire a query which is something like this.

db.users.find({"addresses.name":"home","addresses.state":"NY"});

the output of this query is a single record with the username as kbanker

This implies that it is exactly matching both the parameters "name":"home and addresses.state:NY and returning only one record.

However as per my understanding, this should return both the records since it should check for any of the parameters "name":"home" and addressess.state:NY in the enitre array and if any of them matches it should display that record.

This behavior of selecting just a single record defeats the purpose of $elemMatch attribute ?

Am I correct or something has changed in the new version of mongodb. I am using 3.2.5

Upvotes: 1

Views: 8134

Answers (1)

Koitoer
Koitoer

Reputation: 19543

Let me try to explain using your data set

db.foo.insert({
        "username" : "pbakkum",
        "addresses" : [
                {
                        "name" : "home",
                        "state" : "CA"
                },
                {
                        "name" : "work",
                        "state" : "CA"
                }
        ]
});
db.foo.insert({
        "username" : "kbanker",
        "addresses" : [
                {
                        "name" : "home",
                        "state" : "NY"
                },
                {
                        "name" : "work",
                        "state" : "NY"
                }
        ]
});

When you execute the query db.foo.find({"addresses.name":"home","addresses.state":"NY"}); mongo search in the array for documents that have "home" and "NY" it does not matter if the values are in the same document or not.

> db.foo.find({"addresses.name":"home","addresses.state":"NY"}, { "_id":0, "user
name" :1, "addresses" :1 })
{ "username" : "kbanker", "addresses" : [ { "name" : "home", "state" : "NY" }, {
 "name" : "work", "state" : "NY" } ] }

As you can see it will be enough to have "home" and "NY" in one of the array documents, the difference with $elemMatch is that both of them ("home" and "NY") need to be in the same document.

Lets add another document in the array of the username pbakkum.

db.foo.insert({
        "username" : "pbakkum",
        "addresses" : [
                {
                        "name" : "home",
                        "state" : "CA"
                },
                {
                        "name" : "work",
                        "state" : "CA"
                },
                {
                        "name" : "work",
                        "state" : "NY"  // Adding NY to make the match of your query
                }
        ]
});

Running the same query, this time you will see both records as both of them in the array contain "home" and "NY" in one of the documents

> db.foo.find({"addresses.name":"home","addresses.state":"NY"}, { "_id":0, "user
name" :1, "addresses" :1 })
{ "username" : "pbakkum", "addresses" : [ { "name" : "home", "state" : "CA" }, {
 "name" : "work", "state" : "CA" }, { "name" : "work", "state" : "NY" } ] }
{ "username" : "kbanker", "addresses" : [ { "name" : "home", "state" : "NY" }, {
 "name" : "work", "state" : "NY" } ] }

$elemMatch get only the document that have the perfect match within the same document ("home" and "NY")

> db.foo.find( { addresses : {$elemMatch : {"name":"home","state":"NY"}}}, { "_i
d":0, "username" :1, "addresses" :1 })
{ "username" : "kbanker", "addresses" : [ { "name" : "home", "state" : "NY" }, {
 "name" : "work", "state" : "NY" } ] }

This implies that it is exactly matching both the parameters "name":"home and addresses.state:NY and returning only one record.

Yes query is matching both parameters but not interesting if they are in the same document, this is just a coincidence.

Upvotes: 3

Related Questions