Skip to content

MongoDB - Covered Queries

This chapter explores one of the most powerful performance optimization techniques in MongoDB: the covered query.

A covered query is a query that can be satisfied entirely using an index, without needing to examine any documents. This is possible when:

  • All the fields used in the query’s filter are part of the index.
  • All the fields returned by the query’s projection are also in the same index.

Since indexes are stored in a highly efficient data structure in RAM, MongoDB can answer a covered query extremely fast. It avoids the much slower process of fetching documents from disk, which is a major performance bottleneck.

Consider a users collection with documents like this:

{
"_id": ObjectId("64f8a55b23e8b1e1ab654321"),
"username": "johndoe",
"status": "active",
"reputation": 250
}

First, let’s create a compound index on the status and username fields to support our query.

// Using mongosh
db.users.createIndex({ status: 1, username: 1 })

Now, we can execute a query that is ‘covered’ by this index. Notice the projection explicitly requests username and status, and excludes _id.

db.users.find(
{ status: "active" }, // Query filter uses an indexed field
{ username: 1, status: 1, _id: 0 } // Projection uses only indexed fields
)

To confirm that a query is covered, we use the .explain('executionStats') method.

db.users.find(
{ status: "active" },
{ username: 1, status: 1, _id: 0 }
).explain('executionStats')

The output will be a large JSON object. Look for these key indicators:

  • In queryPlanner.winningPlan.stage, you will see PROJECTION_COVERED instead of PROJECTION_DEFAULT.
  • The stage preceding it will be IXSCAN (Index Scan), not COLLSCAN (Collection Scan).
  • In executionStats, totalDocsExamined will be 0. This is the definitive proof: MongoDB did not need to look at a single full document to return the result.

By default, MongoDB always returns the _id field. If your index does not include _id, but you forget to explicitly exclude it in your projection (_id: 0), the query will not be covered. MongoDB will have to fetch the full document just to get the _id, defeating the purpose.

// THIS QUERY IS NOT COVERED because _id is not in the index
db.users.find({ status: "active" }, { username: 1, status: 1 })

While a multikey index on an array field can be used in a covered query, it has certain limitations. A covered query cannot be used if the query projects an array field that is indexed with a multikey index.