Muhammed Basil
Muhammed Basil

Reputation: 1834

Mongoose get docs matching the array

I have a schema like this

{
    members: [{
         type: Schema.Types.ObjectId,
         ref: 'User'
    }]
    createdAt: {
        type: Date,
        default: Date.now
    }
    ...
}

And the docs are

1-

{
    members:
    ["some id 1", "some id 2"]
},
createdAt: "someTime ago"

2-

{
    members:
    ["some id 1", "some id 2", "some id 3"]
},
createdAt: "someTime ago"

I want to find the docs which match the exact an array of elements

['some id 1', 'some id 2']

ie doc 1 in the above sample docs

How this could be possible?
Any help would be appreciated.

Upvotes: 13

Views: 18159

Answers (1)

Neil Lunn
Neil Lunn

Reputation: 151112

As long as you do realize that you are matching on the ObjectId and not actually anything in the referenced collection you can use the $in operator:

db.collection.find({ "members": { "$in": [ "some id 1", "some id 2" ] } })

Where of course those are your actual ObjectId values.

But if you really mean a document that has exactly that array, then you just pass in the array:

db.collection.find({ "members": [ "some id 1", "some id 2" ] })

And if it must have both the elements but could have others then currently you need to use an $and expression:

db.collection.find({ "$and": [ 
    { "members": "some id 1" },
    { "members": "some id 2" } 
]})

But from release 2.6 an on-wards you can properly use the $all operator to effectively do the same:

db.collection.find({ "members": { "$all": [ "some id 1", "some id 2" ] } })

The other form is matching those two elements only, but in any order. So there are two approaches:

db.collection.find({ "$or": [
    { "members": [ "some id 1", "some id 2" ] },
    { "members": [ "some id 2", "some id 1" ] }
]})

This uses a logical $or to say that the array must be exact but can be arranged either way. And the other approach:

db.collection.find({ "$and": [ 
    { "members": "some id 1" },
    { "members": "some id 2" }
    { "members": { "$size": 2 } }
]})

So this would use $size in order to make sure that when the array contained both of the elements that matched that is also only had just two elements. Which is a nicer syntax than using $or, especially for larger arrays.

And in the future releases as mentioned this gets even cleaner:

db.collection.find({ "$and": [ 
    { "members": { "$all": [ "some id 1", "some id 2" ] } },
    { "members": { "$size": 2 } }
]})

That fairly much covers every interpretation

Upvotes: 35

Related Questions