How do I query an array of dictionaries in MongoDB?

Viewed 8735

I have an array of dictionaries on which I have to make queries. The queries will be like when "name" is "a" then "value" should be "2".

{
    "t": "m",
    "y": "n",
    "A":[ 
            {
             "name": "x",
             "value": "1"
            },
            {
             "name": "y",
             "value": "2"
            },
            {
             "name": "z",
             "value": "1"
            }
        ]
}

In the above, I want to know what are the records whose "value" is "1" when "name" is x. I also need to make queries like, where "name" is "x" then value should be "2" and "name" is "y" then "value" should be "1"

3 Answers

You have to use $elemMatch to query embedded documents in an array if you want to query with multiple fields of embedded document. So your query should be like this:

db.collection.find( {
  "A": { $elemMatch: { name: "x", value: "1" } }
})

If you want query documents which have (name:"x", value:"1") or (name:"y", value:"2") in same query, you can use $orwith elemMatch like this:

db.collection.find( {
  $or: [
    { "A": { $elemMatch: { name: "x", value: "1" } } },
    { "A": { $elemMatch: { name: "y", value: "2" } } }
  ]  
})

If you want query documents which have (name:"x", value:"1") and (name:"y", value:"2") in same query, you can use $andwith elemMatch like this:

db.collection.find( {
  $and: [
    { "A": { $elemMatch: { name: "x", value: "1" } } },
    { "A": { $elemMatch: { name: "y", value: "2" } } }
  ]  
})

I am using it like this and it's working.

db.collection.find(
                  {
                  $and:[
                       {"A.name":"x", "A.value": "2"},
                       {"A.name":"y", "A.value": "3"}, 
                       {"t": "m"}
                       ]
                  }

The above will give all records where "t" is "m" and where dictionary with name "x" has value "2" and dictionary with name "y" has value "3".

One approach is to use $unwind and $match to get the desired result $unwind will unwind the array A, and then using $match we can pick out the matching documents.

Sample query

db.collectionname.aggregate([
      {$unwind:"$A"}, 
      {$match:{"A.name":"x", "A.value":"1"}}
])

Sample result

{ "_id" : ObjectId("59c9ee65f1287059437fa3ac"), "t" : "m", "y" : "n", 
   "A" : { "name" : "x", "value" : "1" } }
Related