Skip to content

$match, $project, $sort, $limit, $skip

These stages are the foundation of most aggregation pipelines.

$match filters documents. It uses the same query syntax as find().

db.orders.aggregate([
{ $match: { status: "completed" } }
])

Filter by date:

db.orders.aggregate([
{
$match: {
createdAt: {
$gte: new Date("2024-01-01"),
$lt: new Date("2025-01-01")
}
}
}
])

Best practice: put $match as early as possible so later stages process fewer documents.

$project controls the output shape.

Include fields:

{ $project: { name: 1, email: 1, _id: 0 } }

Rename fields:

{
$project: {
_id: 0,
customerName: "$name",
customerEmail: "$email"
}
}

Create computed fields:

{
$project: {
name: 1,
priceWithTax: { $multiply: ["$price", 1.18] }
}
}

Sort ascending with 1, descending with -1.

{ $sort: { createdAt: -1 } }

Sort by multiple fields:

{ $sort: { category: 1, price: -1 } }

Keep only a fixed number of documents.

{ $limit: 10 }

Skip documents. Commonly used with pagination.

db.products.aggregate([
{ $sort: { createdAt: -1 } },
{ $skip: 20 },
{ $limit: 10 }
])

For large page numbers, prefer range-based pagination using an indexed field like _id or createdAt.