Vì $match đứng đầu pipeline là stage duy nhất còn dùng được index.
Sau khi dữ liệu đã đi qua $group, $project hay $unwind, nó chỉ còn nằm trong bộ nhớ — mọi $match sau đó phải quét tuần tự.
js
// tốt: lọc trước, giảm dữ liệu đi vào các stage sau
db.orders.aggregate([
{ $match: { createdAt: { $gte: startOfMonth } } },
{ $unwind: '$items' },
{ $group: { _id: '$items.sku', total: { $sum: '$items.qty' } } }
])Hai điểm liên quan hay bị hỏi kèm:
- $unwind nhân dòng: một order có 10 item sẽ thành 10 document trong pipeline. Đặt $unwind sau $match để không nhân dữ liệu thừa.
- $facet chạy nhiều nhánh trên cùng một tập input, tiện cho việc vừa lấy trang dữ liệu vừa đếm tổng trong một lần gọi — nhưng các stage bên trong $facet không dùng được index.
Optimizer của MongoDB có tự đẩy $match lên trước trong một số trường hợp, nhưng không phải lúc nào cũng làm được — viết đúng thứ tự ngay từ đầu là chắc chắn hơn.