MongoDB $count Stage

Beginner
5 min read
Updated: Oct 2026
3 examples
Live preview

What Is $count?

$count is a MongoDB aggregation stage that tallies how many documents reach that point in the pipeline and returns one summary document with a field name you choose.

Remember
$count = "how many docs made it here?"

db.orders.aggregate([
  { $match: { status: "shipped" } },
  { $count: "shippedTotal" }
])
// → [ { shippedTotal: 3 } ]

string argument = output field name
no $ and no dots in the name
zero matches → empty result (not 0)
shortcut for $group + $sum: 1

Outside a pipeline → countDocuments()
UsePrefer
Count after pipeline filters$count
Simple query count (no pipeline)countDocuments()
Fast metadata collection total$collStats count

How to Use $count in MongoDB

Filter first (optional), then place $count at the end with a clear field name.

  1. Optionally filter with $match (or transform with other stages).
  2. Add { $count: "fieldName" } as a later stage (often last).
  3. Read the single result document: { fieldName: N }.
  4. Handle an empty cursor when nothing matched (no zero document).
PieceRequired?Role
Field name stringYesName of the count field in the output
Prior stagesNoDecide which documents are counted
Output—One document, or none if count is 0

Pseudocode

Pseudocode
docs = documents reaching this stage
n = length(docs)

if n == 0:
  emit nothing          // empty cursor
else:
  emit { fieldName: n }

// Same idea as:
// $group { _id: null, fieldName: { $sum: 1 } }
// then drop _id

Cheat Sheet

Keep these facts handy while writing count pipelines.

TopicDetail
TypeAggregation stage
ArgumentNon-empty string (output field name)
Name rulesNo leading $, no . in the name
Output{ fieldName: N } — one document
Zero matchesEmpty result (not 0)
Typical placeAfter $match / $group
Equivalent$group + $sum: 1

Live Preview

Filter the sample orders by status and see what $count would return (including the empty case).

Orders: 3 shipped, 2 pending, 1 cancelled (6 total).

Result
pipeline: [ { $count: "total" } ]
matched: 6
result: [ { total: 6 } ]

Worked Walkthrough — High-Value Shipped

Six orders. Goal: count shipped orders with amount >= 50.

Calculation
Orders:
  Keyboard  45  shipped   → drop (amount < 50)
  Mouse     25  pending   → drop (status)
  Monitor  220  shipped   → keep
  Webcam    60  pending   → drop (status)
  Headset   80  shipped   → keep
  Dock      95  cancelled → drop (status)

After $match → 2 documents
$count: "highValueShipped" → [ { highValueShipped: 2 } ]

MongoDB Examples

We use a small orders collection. First count after a filter, then count how many groups $group created. Run these in mongosh after inserting the sample data once.

Example 1 — Sample Data

Six orders across three statuses and two regions—enough variety for filtered counts and group counting.

mongosh
db.orders.drop()
db.orders.insertMany([
  { product: "Keyboard", amount: 45,  status: "shipped",   region: "East" },
  { product: "Mouse",    amount: 25,  status: "pending",   region: "West" },
  { product: "Monitor",  amount: 220, status: "shipped",   region: "East" },
  { product: "Webcam",   amount: 60,  status: "pending",   region: "East" },
  { product: "Headset",  amount: 80,  status: "shipped",   region: "West" },
  { product: "Dock",     amount: 95,  status: "cancelled", region: "West" }
])

How the Data Is Stored in MongoDB

After the insert, MongoDB keeps six documents in orders. Run find() to see them:

mongosh
db.orders.find()

Read the important fields like this:

FieldExamplePlain English
status"shipped"Order state we often filter on
amount45 … 220Order total for high-value filters
region"East"Region used when counting groups

How It Works

  1. Reset once. drop() keeps the demo repeatable.
  2. Insert six orders. Mixed statuses give useful $match counts.
  3. Ready for counting. Next examples tally these rows (or groups of them).

Example 2 — Count After $match

Goal: count shipped orders with amount >= 50. This is the most common $count pattern in APIs.

mongosh
db.orders.aggregate([
  {
    $match: {
      status: "shipped",
      amount: { $gte: 50 }
    }
  },
  { $count: "highValueShipped" }
])

// Count everything (no filter):
// db.orders.aggregate([{ $count: "totalOrders" }])
// → [ { totalOrders: 6 } ]

How It Works

  1. Filter first. $match keeps only shipped orders with amount at least 50.
  2. Count what remains. Two documents reach $count.
  3. Name the field. Output becomes { highValueShipped: 2 }.
  4. Empty tip: if nothing matched, the cursor is empty—not { highValueShipped: 0 }.

Example 3 — Count Groups

Goal: after $group, count how many buckets were created (distinct statuses)—not the original order rows.

mongosh
// How many distinct status values?
db.orders.aggregate([
  { $group: { _id: "$status" } },
  { $count: "statusCount" }
])
// → [ { statusCount: 3 } ]
//    shipped | pending | cancelled

// Zero matches → empty array (not zero)
db.orders.aggregate([
  { $match: { status: "refunded" } },
  { $count: "refundedTotal" }
])
// → []

// Outside a pipeline, countDocuments always returns a number:
// db.orders.countDocuments({ status: "refunded" }) → 0

How It Works

  1. Group first. $group by status emits one document per distinct value.
  2. Count buckets. Three groups reach $count → statusCount: 3.
  3. Different question. You counted categories, not original order rows.
  4. Empty vs zero. A filter with no hits returns []; countDocuments returns 0.

Edge Cases & Pitfalls

Check these before relying on $count in APIs.

empty

Zero matches return nothing

You do not get { total: 0 }. Treat an empty cursor as zero in application code when needed.

name

Field name rules are strict

Non-empty string only. Cannot start with $ and cannot contain a dot (.).

place

Stages after $count see one doc

$count collapses the stream. Anything after it operates on the summary row, not the original documents.

vs

Not the same as metadata count

For a quick collection total from metadata, use $collStats. For filtered pipeline totals, use $count.

Performance Notes

ApproachCostBest for
$match then $countScan / index + tallyFiltered API totals
countDocuments(filter)Query countSimple counts outside pipelines
$collStats countMetadataFast whole-collection estimate

Put selective $match early so indexes can reduce documents before $count. Prefer countDocuments when you do not need other aggregation stages.

Key Takeaways

  • Role: tally documents that reached this stage.
  • Output: one document { yourField: N }.
  • Pattern: $match (or $group) then $count.
  • Zero: empty cursor—not a zero field.

One line: $count answers “how many documents made it this far in the pipeline?”

Frequently Asked Questions

$count tallies how many documents reach that point in the aggregation pipeline and returns one document like { myTotal: 42 }. The string argument is the output field name. It is a shortcut for $group with $sum: 1 plus dropping _id.
Usually at the end after filters: [{ $match: { status: "shipped" } }, { $count: "shippedTotal" }]. You can also place it after $group to count how many groups were formed.
countDocuments() counts matching query documents outside a pipeline. $count runs inside aggregate() after prior stages, so the total reflects filtered or transformed pipeline output.
MongoDB returns no result document at all—not { total: 0 }. Handle an empty cursor in your app, or use patterns that always emit a zero when you need one.
The argument must be a non-empty string, cannot start with $, and cannot contain a dot (.). Example: { $count: "orderTotal" } outputs { orderTotal: N }.
$count tallies documents that flowed through your pipeline. $collStats { count: {} } reads fast collection metadata and may be approximate on sharded clusters.

Next: $currentOp

See what operations are running right now—useful for debugging slow queries.

$currentOp tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

9 people found this page helpful