What is the functional difference between:
db.docs.find({ 'a.b': 'c' }, { 'a.$': 1 })
and
db.docs.find({ 'a.b': 'c' }, { 'a': { $elemMatch: { b: 'c' } } })
Is $elemMatch redundant? How would indexes change?
The difference in projection usage is somewhat subtle. In your example usage, these should be equivalent queries (in terms of index usage) but the $elemMatch
example unnecessarily repeats the query criteria. The $
projection would be a more sensible choice for this example.
An essential difference noted in the documentation is the array field limitation for $
projections:
Since only one array field can appear in the query document, if the array contains documents, to specify criteria on multiple fields of these documents, use the $elemMatch operator.
Some further notes on the differences in the projection operators below ...
$
) projection operator:limits the contents of an array field that is included in the query results to contain the first element that matches the query document.
requires that the matching array field is included in the query criteria
can only be used if a single array field appears in the query criteria
can only be used once in a projection
$elemMatch
projection operator
limits the contents of an array field that is included in the query results to contain only the first array element that matches the $elemMatch condition.
does not require the matching array to be in the query criteria
can be used to match multiple conditions for array elements that are embedded documents
$elemMatch
query operator
Note that there is also an $elemMatch
query operator which performs similar matching, but in the query rather than the results projection. It's not uncommon to see this used in combination with a $
projection.
Borrowing an example from the docs where you might use both:
db.students.find(
// use $elemMatch query operator to match multiple criteria in the grades array
{ grades: {
$elemMatch: {
mean: { $gt: 70 },
grade: { $gt: 90 }
}
}},
// use $ projection to get the first matching item in the "grades" array
{ "grades.$": 1 }
)
If you use $elemMatch alone, in find projection,
$elemMatch will not filter documents (conditions not applied)
Suppose, 'students' contains the following documents
{ "_id" : 1, "semester" : 1, "grades" : [ 70, 87, 90 ] }
{ "_id" : 2, "semester" : 1, "grades" : [ 90, 88, 92 ] }
{ "_id" : 3, "semester" : 1, "grades" : [ 85, 100, 90 ] }
{ "_id" : 4, "semester" : 2, "grades" : [ 79, 85, 80 ] }
{ "_id" : 5, "semester" : 2, "grades" : [ 88, 88, 92 ] }
{ "_id" : 6, "semester" : 2, "grades" : [ 95, 90, 96 ] }
{
"_id" : 7,
"semester" : 3,
"grades" : [
{
"grade" : 80,
"mean" : 75,
"std" : 8
},
{
"grade" : 85,
"mean" : 90,
"std" : 5
},
{
"grade" : 90,
"mean" : 85,
"std" : 3
}
]
}
{
"_id" : 8,
"semester" : 3,
"grades" : [
{
"grade" : 92,
"mean" : 88,
"std" : 8
},
{
"grade" : 78,
"mean" : 90,
"std" : 5
},
{
"grade" : 88,
"mean" : 85,
"std" : 3
}
]
}
the below query will return all the documents in collection,
db.students.find({},{ grades: { $elemMatch: { mean: 90 } } } ).pretty()
where as, below query returns only the matching records
db.students.find({"grades.mean":90},{"grades.$":1}).pretty()
i hope Indexes do not make any difference in either queries
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