24. Aggregation Performance, Indexes, and Optimization
Optimize only after verifying correctness. An early selective $match can reduce work and may use a source index. Index eligibility depends on pipeline shape, predicates, index order, and data distribution.
Avoid unnecessary $unwind, project away large unused fields where useful, and be careful with blocking stages such as $sort and $group. Some stages can spill to disk under supported conditions, but resource behavior varies; $facet has particular restrictions. Index foreign lookup fields where appropriate.
Use explain("executionStats") for important pipelines. Inspect the plan, documents examined, returned documents, index use, and stage statistics. Benchmark with realistic data instead of assuming an index or rewrite is beneficial.
Use explain output and realistic benchmarks before adding indexes or rewriting a pipeline.
db.orders.createIndex({ status: 1, createdAt: -1 });
db.orders.explain("executionStats").aggregate([
{ $match: { status: "delivered", createdAt: { $gte: ISODate("2026-10-01T00:00:00Z"), $lt: ISODate("2026-11-01T00:00:00Z") } } },
{ $sort: { createdAt: -1, _id: -1 } },
{ $limit: 20 },
{ $project: { customerId: 1, status: 1, createdAt: 1 } }
]);- Filter early when semantics allow.
- Index use depends on query shape.
- Unwinding, sorting, grouping, and joining can dominate cost.
- Benchmark representative workloads.
How should you confirm whether an aggregation benefits from an index?