The $facet stage runs several sub-pipelines in parallel on the same input documents—returning one document with multiple result arrays, like a dashboard with filters, charts, and a paginated table from a single query.
01
Parallel pipes
Many views, one pass.
02
Named outputs
Each key → array.
03
Page + count
Classic API pattern.
04
Faceted search
Tags, price, year.
05
$match first
Index-friendly.
06
Memory limits
100 MB per facet.
Fundamentals
Definition and Usage
$facet is an aggregation stage that fans out input documents into multiple independent pipelines. MongoDB reads the input set once, runs every sub-pipeline, and merges results into a single output document.
💡
Beginner tip
Think of $facet like splitting one spreadsheet into several pivot tables at the same time. E-commerce sites use it for sidebar filters (category counts, price ranges) while also returning the product list—without three separate database round trips.
Use $facet for admin dashboards, faceted product search, and pagination metadata. Pair sub-pipelines with $sortByCount, $bucket, and $count.
Foundation
📝 Syntax
$facet maps output field names to arrays of pipeline stages:
Single document with named arrays
topSellers → ranked list
byCategory → count per category
How It Works
Both sub-pipelines read all six products independently. MongoDB returns one document containing both result arrays—your API can map them directly to UI widgets.
📈 Practical Patterns
Pagination, multi-faceted search, and performance tips.
Example 3 — Paginated list + total count (API pattern)
items → current page rows
meta[0].total → full match count
One DB round trip instead of two
How It Works
This is the most common production use of $facet. The items branch paginates; the meta branch counts—all on the same filtered Electronics set from $match.
Example 4 — Multi-faceted search (tags, price, year)
categorizedByTags → tag counts
categorizedByPrice → price tiers
categorizedByYear → year histogram
How It Works
Matches MongoDB’s official artwork example pattern. Retail search UIs render each facet array as checkbox filters while the main product grid uses a separate query or another facet branch.
$facet is MongoDB’s built-in way to run parallel aggregations on one filtered dataset. Name your output fields, define sub-pipeline stage arrays, and return dashboards or paginated APIs in a single query.
Filter with $match first, use $limit in heavy facets, and remember memory caps. Next: $geoNear for location-based pipelines.
Place $match before $facet for index use and smaller input
Use $facet for page rows + total count in one API call
Add $limit to sub-pipelines that could return huge arrays
Name facet fields to match your API response schema
Combine $sortByCount, $bucket for search sidebar filters
❌ Don’t
Start pipelines with $facet when the collection is large
Nested $facet or use forbidden stages inside sub-pipelines
Assume sub-pipelines can pass data to each other within one $facet
Return unbounded arrays that exceed 100 MB or 16 MB BSON limits
Replace $lookup joins with $facet—different purposes
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about $facet
Use these points whenever you build multi-summary pipelines.
5
Core concepts
🔀01
Parallel pipes
Same input once.
Basics
📦02
Named arrays
One doc out.
Output
📄03
Page + count
API pattern.
Pattern
🔍04
$match first
Index friendly.
Perf
⚠️05
100 MB cap
Per sub-pipe.
Limit
❓ Frequently Asked Questions
$facet runs multiple independent aggregation sub-pipelines on the same set of input documents in one stage. Each sub-pipeline's results are stored as an array in a named output field—ideal for dashboards that need several summaries from one filtered dataset.
{ $facet: { fieldName1: [ stage1, stage2, … ], fieldName2: [ … ] } }. Each key is the output field name; each value is an array of pipeline stages. $facet returns exactly one document containing all facet arrays.
No. All sub-pipelines receive the same input documents from prior stages, but one sub-pipeline's output cannot feed another inside the same $facet. Chain additional stages after $facet and reference a facet field if you need further processing.
Restricted stages include $facet (nested), $out, $merge, $geoNear, $collStats, $indexStats, $planCacheStats, $search, $searchMeta, and $vectorSearch.
Use $facet with two sub-pipelines on the same $match input: items: [{ $skip: N }, { $limit: M }] and meta: [{ $count: "total" }]. Both run in parallel—one round trip for page + count.
If $facet is the first stage, it performs a collection scan. Put $match or $sort before $facet so earlier stages can use indexes; $facet then processes the filtered set without triggering its own COLLSCAN.
Did you know?
The name $facet comes from faceted search in e-commerce—showing counts per filter dimension (brand, price range, size) so shoppers can narrow results. MongoDB reads input documents once, so three facet branches cost less than three separate full-collection scans. See the official $facet docs.