Search code examples
mongodbsubdocument

In Mongo query in Subdocuments multiple fields


I have a collection in Mongo

{
  "_id": 1,
  "favorites": {
    "artist": "Picasso",
    "food": "pizza"
  },
  "finished": [
    17,
    3
  ],
  "badges": [
    "blue",
    "black"
  ],
  "points": [
    {
      "points": 85,
      "bo nus": 20
    },
    {
      "points": 85,
      "bonus": 10
    }
  ]
}{
  "_id": 2,
  "favorites": {
    "artist": "Miro",
    "food": "meringue"
  },
  "finished": [
    11,
    25
  ],
  "badges": [
    "green"
  ],
  "points": [
    {
      "points": 85,
      "bonus": 20
    },
    {
      "points": 64,
      "bonus": 12
    }
  ]
}{
  "_id": 3,
  "favorites": {
    "artist": "Cassatt",
    "food": "cake"
  },
  "finished": [
    6
  ],
  "badges": [
    "blue",
    "red"
  ],
  "points": [
    {
      "points": 85,
      "bonus": 8
    },
    {
      "points": 55,
      "bonus": 20
    }
  ]
}{
  "_id": 4,
  "favorites": {
    "artist": "Chagall",
    "food": "chocolate"
  },
  "finished": [
    5,
    11
  ],
  "badges": [
    "red",
    "black"
  ],
  "points": [
    {
      "points": 53,
      "bonus": 15
    },
    {
      "points": 51,
      "bonus": 15
    }
  ]
}{
  "_id": 5,
  "favorites": {
    "artist": "Noguchi",
    "food": "nougat"
  },
  "finished": [
    14,
    6
  ],
  "badges": [
    "orange"
  ],
  "points": [
    {
      "points": 71,
      "bonus": 20
    }
  ]
}{
  "_id": 6,
  "favorites": {
    "food": "pizza",
    "artist": "Picasso"
  },
  "finished": [
    18,
    12
  ],
  "badges": [
    "black",
    "blue"
  ],
  "points": [
    {
      "points": 78,
      "b onus": 8
    },
    {
      "points": 57,
      "bonus": 7
    }
  ]
}

I want to retrieve all elements having points = 85 and bonus = 20. Query will be

db.temp2.find({"points":{"points":85,"bonus":20}})

it returns documents with id : 1 and 2.

Now if i want to retrieve elements having ( points=85 and bonus = 20 ) and another sub-documents with {points=85 and bonus > 10). basically i want to retrieve element with id = 2

if query is

 db.temp2.find({$and:[{"points":{"points":85,"bonus":20}},{"points":{"points":64,"bonus":{$gte:10}}}]}).pretty()

it gives no results whereas query

 db.temp2.find({$and:[{"points":{"$elemMatch":{"points":85,"bonus":20}}},{"points":{"$elemMatch":{"points":64,"bonus":{$gte:10}}}}]})

gives me id=2.

Same thing i tried with anther sets

[
  {
    "name": "User1",
    "tags": [
      {
        "k": "group",
        "v": "test"
      },
      {
        "k": "color",
        "v": "blue"
      }
    ]
  },
  {
    "name": "User2",
    "tags": [
      {
        "k": "group",
        "v": "dev"
      },
      {
        "k": "color",
        "v": "blue"
      }
    ]
  },
  {
    "name": "User3",
    "tags": [
      {
        "k": "group",
        "v": "dev"
      },
      {
        "k": "color",
        "v": "red"
      }
    ]
  }
]

and if you want to find out elements having

"tags": [
      {
        "k": "group",
        "v": "dev"
      },
      {
        "k": "color",
        "v": "blue"
      }
    ] 

query :

db.temp4.find({$and:[{"tags":{"k":"group","v":"dev"}},{"tags":{"k":"color","v":"blue"}}]})

and

db.temp4.find({$and:[{"tags":{"$elemMatch":{"k":"group","v":"dev"}}},{"tags":{"$elemMatch":{"k":"color","v":"blue"}}}]})

in both case you will get response.

Please help me to understand when to use $elemMatch and "$and".

Thanks in advance. Sorry for grammatical mistakes.


Solution

  • The below query should work. As it is an embedded array, the "points.bonus" and "points.points" should be referred like this when $gte is used.

    db.collection.find({$and:[{"points":{"points":85,"bonus":20}}, {"points.points" : 64, "points.bonus" : {$gte : 10}}]})
    

    In the second example, there is no $gte. So, you are getting response for both queries.