Reputation: 1834
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
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