Is there any logical difference between the usage of the query operator $and
db.collection.find({$and: [{"array.field1": "someValue"}, {"array.field2": 3}]})
and the usage of the projection operator $elemMatch
db.collection.find({array: {$elemMatch: {field1: "someValue", field2: 3}}})
to find documents which contain the object fields inside an array?
I will explain this with an example. Consider the collection arrays
. It has a field called arr
which is an array of embedded documents (with fields a
and b
).
Some documents in the arrays
collection:
{ "_id" : 1, "arr" : [ { "a" : "a1", "b" : "b1" }, { "a" : "a2", "b" : "b2" } ] }
{ "_id" : 2, "arr" : [ { "a" : "a1", "b" : "b11" }, { "a" : "a2", "b" : "b22" } ] }
{ "_id" : 3, "arr" : [ { "a" : "a2", "b" : "b1" }, { "a" : "a", "b" : "b1" } ] }
{ "_id" : 4, "arr" : [ { "a" : "a1", "b" : "b91" }, { "a" : "a29", "b" : "b1" } ] }
I want to find all documents with the array embedded-document fields a="a1"
AND b="b1"
. Note this must be within the same element embedded-document of the array. I use $elemMatch for this and get the desired result.
> db.arrays.find( { arr: { $elemMatch: { a: "a1", b: "b1" } } } )
==>
{ "_id" : 1, "arr" : [ { "a" : "a1", "b" : "b1" }, { "a" : "a2", "b" : "b2" } ] }
Now, if I use the $and operator like in the following query, the results are not correct. As you can see an additional document is selected. The query worked with the array embedded-document fields a="a1"
OR b="b1"
.
> db.arrays.find({$and: [ { "arr.a": "a1" }, { "arr.b": "b1" } ] } )
==>
{ "_id" : 1, "arr" : [ { "a" : "a1", "b" : "b1" }, { "a" : "a2", "b" : "b2" } ] }
{ "_id" : 4, "arr" : [ { "a" : "a1", "b" : "b91" }, { "a" : "a29", "b" : "b1" } ] }
So, using the $and
operator is NOT intended for this purpose (i.e., querying on multiple fields of an array of sub-documents).
Also, to query on an array embedded-document field (only one field) the $elemMatch
is not required, for example:
> db.arrays.find( { "arr.a": "a2" } )
==>
{ "_id" : 1, "arr" : [ { "a" : "a1", "b" : "b1" }, { "a" : "a2", "b" : "b2" } ] }
{ "_id" : 2, "arr" : [ { "a" : "a1", "b" : "b11" }, { "a" : "a2", "b" : "b22" } ] }
{ "_id" : 3, "arr" : [ { "a" : "a2", "b" : "b1" }, { "a" : "a", "b" : "b1" } ] }
Your first query will find documents, where array have at least one element with field1= somevalue and at least one element with field2=3. Both elements can be different. The second one will retrieve documents where array have at least one element matching the two conditions simultaneously. Here's a data sample to explain :
{
array: [
{
field1: 1,
},
{
field2: 2
},
{
field1: 1,
field2: 3
},
]
},
{
array: [
{
field1: 1,
field2: 2
},
{
field2: 3
}
]
},
{
array: [
{
field1: 1,
field2: "other"
},
{
field2: 2
}
]
}
The first query
db.collection.find({"array.field1": 1,"array.field2": 2}) (equivalent to your $and syntax)
will returne the three documents,
db.collection.find({array: {$elemMatch: {field1: 1, field2: 2}}})
will return only the second document (the only one having an element matching both criterias)
EDIT : The logical operator of the first query is OR, for the second one it's AND, at level of array element.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With