Optimize a pipeline

Make an aggregation read fewer documents and touch fewer ranges.

Make an aggregation read fewer documents and touch fewer ranges. The router already sends each range the part of the pipeline it can do alone; you decide how much that part filters.

Requirements

  • A connection with a user that has read on the database.

Filter as early as possible

Put $match and $project at the start, on indexed fields. Those stages run on each range before results are merged.

Sort with a limit

A $sort followed by $limit becomes a top-k per range, which reads far less than sorting everything.

Look at the plan

JavaScript
db.orders.explain("executionStats").aggregate([{ $match: { status: "paid" } }, { $group: { _id: "$customer" } }]);

Check

explain shows the ranges touched and how many documents each stage read; the numbers drop when you filter earlier.

Common problems

  • A $match after $group cannot use indexes or run on each range; move it earlier if it filters fields of the documents.

See also