Parth Vyas
Parth Vyas

Reputation: 507

Mongodb nested find

My database schema is somewhat like

{ 
    "_id" : ObjectId("1"), 
    "createdAt" : ISODate("2017-03-10T00:00:00.000+0000"), 
    "user_list" : [
        {
            "id" : "a", 
            "some_flag" : 1,  
        }, 
        {
            "id" : "b",
            "some_flag" : 0, 
        }
    ]
}

What I want to do is get the document where id is b & some_flag for the user b is 0.

My query is

db.collection.find({
  'createdAt': {
    $gte: new Date()
  },
  'user_list.id': 'b',
  'user_list.some_flag': 1
}).sort({
  createdAt: 1
})

When I run the query in shell. It returns the doc with id 1(which it shouldn't as the value of some_flag for b is 0)

The thing happening here is,

the query 'user_list.id': user_id matches with the nested object where "id" : b

'user_list.some_flag': 1 is matched with some_flag of nested object where "id": a (as the value of some_flag is 1 here)

What modifications should I make to compare the id & some_flag for the same nested object.

P.S. the amount of data is quite large & using aggregate will be a performance bottleneck

Upvotes: 1

Views: 4239

Answers (2)

cubbuk
cubbuk

Reputation: 7920

You should be using $elemMatch otherwise mongoDB queries are applied independently on array items, so in your case 'user_list.some_flag': 1 will be matched to array item with id a and 'user_list.id': 'b' will match array item with id b. So essentially if you want to query on array field with and logic use $elemMatch as following:

db.collection.find({
  'createdAt': {
    $gte: new Date()
  },
  user_list: {$elemMatch: {id: 'b', some_flag: 1}} // will only be true if a unique item of the array fulfill both of the conditions.
}).sort({
  createdAt: 1
})

Upvotes: 3

Andy Macleod
Andy Macleod

Reputation: 3069

you need to try something like :

db.collection.find({
    'createdAt': {
        $gte: new Date()
    },
    user_list: {
        $elemMatch: {
            id: 'b',
            some_flag: 1
        }
    }
}).sort({
  createdAt: 1
});

This will match only user_list entries where _id is b and someflag is 1

Upvotes: 3

Related Questions