$projection vs $elemMatch

mongodb

Solution

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 ...

The positional (`$`) 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

The `$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

The `$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 }
)

Problem

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?

Original source