Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB: query nested array by more than one condition

Tags:

mongodb

nosql

Say this is one item from my users collection:

  {
    "_id" : "5545f4c4d0dd52c355a99fbe",
    "name" : "Dollie James",
    "device" : "iOS",
    "gender" : "Female",
    "wallet" : [
        {
            "store" : "All Saints",
            "balance" : "$196.11",
            "date" : "2014-02-22T22:09:38 -10:00",
            "tags" : [
                "Tshirt",
                "Summer"
            ]
        },
        {
            "store" : "Nike",
            "balance" : "$367.76",
            "date" : "2014-04-18T14:44:30 -10:00",
            "tags" : [
                "Shoes"
            ]
        }
    ]
}

This record was returned from the following query:

db.users.findOne({$and:[{"wallet.tags" : "Tshirt"}, {"wallet.store":"Nike"}]})

However this is not the result I want because Tshirt and Nike are not in the same object in the wallet array. It seems that mongo is doing a query on the entire array. How can I target this query to only return my two conditions that are in the same object within the array?

like image 484
squareOne Avatar asked Oct 18 '25 13:10

squareOne


1 Answers

You don't need $and (as it will apply conditions independently) but $elemMatch. From the doc:

The $elemMatch operator matches documents that contain an array field with at least one element that matches all the specified query criteria.

In your specific case:

> db.wallet.find(
              {wallet: { $elemMatch:{"tags" : "Tshirt", "store":"Nike"}}}
  ).pretty()
{
    "_id" : "5545f4c4d0dd52c355a99f00",
    "name" : "Working example",
    "device" : "iOS",
    "gender" : "Female",
    "wallet" : [
        {
            "store" : "Nike",
            "balance" : "$196.11",
            "date" : "2014-02-22T22:09:38 -10:00",
            "tags" : [
                "Tshirt",
                "Summer"
            ]
        }
    ]
}
like image 68
Sylvain Leroux Avatar answered Oct 21 '25 01:10

Sylvain Leroux