ssnitish
ssnitish

Reputation: 155

$elemMatch and $in. query for array of documents

having a collection(productList) and document like below:

    {   "_id":"1",
        "product_name" : "Haier 240l",
        "version" : "1.0",
        "filterInfo" : [ 
            {
                "name" : "brand",
                "value" : "Haier"
            }, 
            {
                "name" : "energy_rating",
                "value" : "4 Star"
            }
         ]
    }
    {   "_id":"2",
        "product_name" : "Haier 310l",
        "version" : "1.0",
        "filterInfo" : [ 
            {
                "name" : "brand",
                "value" : "Haier"
            }, 
            {
                "name" : "energy_rating",
                "value" : "3 Star"
            }
         ]
    }

    {   "_id":"3",
        "product_name" : "Samsung 275l",
        "version" : "1.0",
        "filterInfo" : [ 
            {
                "name" : "brand",
                "value" : "Samsung"
            }, 
            {
                "name" : "energy_rating",
                "value" : "3 Star"
            }
         ]
    }
 {   "_id":"4",
        "product_name" : "Lg 254l",
        "version" : "1.0",
        "filterInfo" : [ 
            {
                "name" : "brand",
                "value" : "Lg"
            }, 
            {
                "name" : "energy_rating",
                "value" : "3 Star"
            }
         ]
    }

I want to fetch all document with (i), brand:Haier and energy_rating:3
And (ii) brand:Haier or brand:Samsung and energy_rating:3
For (i) I tried, using elemMatch below queries:

db.productList.find({filterInfo: { $elemMatch: {'name':{$in:['brand','enery_rating']},'value':{$in:['Samsung','3 Star']}}}})

db.getCollection('productList').find({'filterInfo': {$elemMatch: { 'value':'Samsung', 'value' :'3 Star'} }  })

db.getCollection('productList').find({'filterInfo': {$elemMatch: {   $and:[ {'name':'brand', 'value' :'Samsung'}, {'name':'energy_rating', 'value':'3 Star' } ]} }    }) 

db.getCollection('productList').find({'filterInfo': {$elemMatch: {  'name':'brand', 'value' :'Samsung', 'name':'energy_rating', 'value':'3 Star'} }    })

But none of these is working correctly. I am doing some bascis wrong here (Novice here).

Upvotes: 1

Views: 2782

Answers (2)

Arun Ravindranath
Arun Ravindranath

Reputation: 2261

No need for $elemMatch in this, I would say.

First Query

db.productList.find({
   $and:[
         {'filterInfo.value':'Haier'},
         {'filterInfo.value':'3 Star'}
        ]
});

Second Query

db.productList.find({
   $and:[
         {'filterInfo.value':{
            $in:['Haier','Samsung']}
         },
         {'filterInfo.value':'3 Star'}
        ]
});

Concentrate more on data structuring in MongoDB for optimized performance. I don't know your application logic, But is it necessary to keep all those data in an array. I don't see the need of that when you can keep data simple like JSON 1 or if you are specific about filterInfo key can be designed like JSON 2.

JSON 1

{
    "_id" : "1",
    "product_name" : "Haier 240l",
    "version" : "1.0",
    "brand":"Haier",
    "energy_rating":"4 Star"
}

JSON 2

 {
        "_id" : "1",
        "product_name" : "Haier 240l",
        "version" : "1.0",
        "filterInfo": {
            "brand":"Haier",
            "energy_rating":"4 Star"
            }
 }

Upvotes: 0

s7vr
s7vr

Reputation: 75984

First Query

db.productList.find({
  "$and":[
    {"filterInfo":{"$elemMatch":{"name":"brand","value":"Haier"}}},
    {"filterInfo":{"$elemMatch":{"name":"energy_rating","value":"3 Star"}}}
  ]
})

You can simplify the first query using $all with $elemMatch to perform queries on arrays.

db.productList.find({
  "filterInfo":{
    "$all":[
      {"$elemMatch":{"name":"brand","value":"Haier"}},
      {"$elemMatch":{"name":"energy_rating","value":"3 Star"}}
    ]
  }
})

Second Query

db.productList.find({
  "$and":[
    {"$or":[
      {"filterInfo":{"$elemMatch":{"name":"brand","value":"Samsung"}}},
      {"filterInfo":{"$elemMatch":{"name":"brand","value":"Haier"}}}
    ]},
    {"filterInfo":{"$elemMatch":{"name":"energy_rating","value":"3 Star"}}}
  ]
})

Upvotes: 2

Related Questions