MongoDB $sample Stage

Beginner
⏱️ 10 min read
📚 Updated: Jul 2026
🎯 5 Examples
Aggregation

What You’ll Learn

The $sample stage randomly picks N documents from the pipeline stream—ideal for quick data previews, QA spot checks, A/B test cohorts, and prototyping without scanning or exporting entire collections.

01

size: N

How many docs.

02

Random pick

Not first-N.

03

First stage

Fast path.

04

After $match

Filtered sample.

05

vs $limit

Random vs top.

06

Testing

QA subsets.

Definition and Usage

$sample is an aggregation stage that outputs a random subset of documents. You specify how many with size—an integer greater than or equal to 1.

💡
Beginner tip

$limit = “give me the first 5 rows.”
$sample = “give me any 5 rows at random.”
Run the same $sample pipeline twice and you may get different documents each time.

For best performance on large collections, put $sample first and keep size small relative to the collection (under roughly 5% of total documents when the collection has 100+ documents).

📝 Syntax

$sample accepts a single option—the number of documents to select:

mongosh
{ $sample: { size: <positive integer N> } }

Syntax Rules

  • size — required. Integer ≥ 1. Number of documents to randomly return.
  • Fewer docs available — if the input has fewer than size documents, all are returned.
  • Fast path — first stage + small size + 100+ collection docs → pseudo-random cursor (efficient).
  • Slow path — otherwise reads all input docs and random-sorts to pick N (memory limits apply).
  • Non-deterministic — results vary between runs unless you persist output (e.g. with $out).
  • Sharded clusters — each shard samples independently; mongos merges and returns N total.
mongosh
db.users.aggregate([
  { $sample: { size: 3 } }
])

⚡ Quick Reference

QuestionAnswer
What it doesRandomly selects size documents from input
Required optionsize — integer ≥ 1
Best performanceFirst stage; small size vs collection count
vs $limit$sample random; $limit first N in order
More than availableReturns all input documents (up to count)
On viewsNever first stage; uses slower scan path
Basic
{ $sample: {
  size: 5
}}

5 random docs

Filtered
$match →
$sample

Random subset

Preview
$sample →
$project

Trim fields

Persist
$sample →
$out

Save cohort

🧰 $sample Option & Behavior

$sample has one parameter—size—but placement and collection size affect how MongoDB executes it:

size Required

Count of documents to return. Must be a positive integer. If fewer documents exist in the input stream, all are returned.

{ $sample: { size: 10 } }
{ $sample: { size: 1 } }  // one random doc
First stage Performance

When $sample is stage 1 on a collection and size is small (< ~5% of docs, 100+ total), MongoDB uses an efficient pseudo-random cursor.

db.orders.aggregate([
  { $sample: { size: 50 } }
])
After filters Pattern

$match first narrows the pool; $sample then picks randomly from matches—e.g. random 5 shipped orders.

{ $match: { status: "active" } },
{ $sample: { size: 5 } }
Large size Caution

When size exceeds ~5% of collection documents, MongoDB random-sorts all input—slower and subject to sort memory limits (100MB spill threshold).

// size 5000 on 10k docs → slow path
// Prefer $match to shrink pool first

Examples Gallery

Users and orders collections—basic random pick, filtered sampling, QA preview pipeline, comparison with $limit, and persisting a random cohort.

📚 Getting Started

Users and orders for sampling labs.

Example 1 — Users and orders collections

mongosh
db.users.drop()
db.orders.drop()

db.users.insertMany([
  { _id: 1, name: "dave123", tier: "gold",   active: true  },
  { _id: 2, name: "dave2",   tier: "silver", active: true  },
  { _id: 3, name: "ahn",     tier: "gold",   active: true  },
  { _id: 4, name: "li",      tier: "bronze", active: false },
  { _id: 5, name: "annT",    tier: "silver", active: true  },
  { _id: 6, name: "li",      tier: "gold",   active: true  },
  { _id: 7, name: "ty",      tier: "bronze", active: true  }
])

db.orders.insertMany([
  { product: "Widget", amount: 99,  status: "shipped",   region: "North" },
  { product: "Gadget", amount: 149, status: "shipped",   region: "South" },
  { product: "Gizmo",  amount: 49,  status: "pending",   region: "East"  },
  { product: "Widget", amount: 99,  status: "shipped",   region: "West"  },
  { product: "Tool",   amount: 199, status: "cancelled", region: "North" },
  { product: "Part",   amount: 25,  status: "shipped",   region: "South" },
  { product: "Kit",    amount: 75,  status: "shipped",   region: "East"  },
  { product: "Pack",   amount: 55,  status: "pending",   region: "West"  }
])

How It Works

Seven users and eight orders—enough to demonstrate random selection, filtered pools, and the difference between $sample and $limit.

Example 2 — Pick 3 random users (basic $sample)

mongosh
db.users.aggregate([
  { $sample: { size: 3 } }
])

// Returns 3 random users from 7
// Run again → likely different 3 (non-deterministic)
// $sample as first stage → efficient on large collections

db.users.aggregate([
  { $sample: { size: 3 } },
  {
    $project: {
      _id: 0,
      name: 1,
      tier: 1
    }
  }
])

How It Works

The simplest form: one stage, one option. Add $project after to trim fields for API previews or console inspection.

Example 3 — Random sample of shipped orders ($match first)

mongosh
db.orders.aggregate([
  { $match: { status: "shipped" } },
  { $sample: { size: 2 } },
  {
    $project: {
      _id: 0,
      product: 1,
      amount: 1,
      region: 1
    }
  }
])

// Pool: 5 shipped orders (after $match)
// $sample picks 2 at random from that pool
// pending/cancelled orders never considered

How It Works

Always filter with $match when the random subset must come from a specific slice—active users, completed orders, or a date range—before sampling.

📈 Practical Patterns

Compare with $limit and build QA workflows.

Example 4 — $sample vs $limit (random vs deterministic)

mongosh
// $limit — first 3 in natural/plan order (same every run)
db.users.aggregate([
  { $limit: 3 }
])
// Typically _id 1, 2, 3 — deterministic

// $sample — any 3 at random (different each run)
db.users.aggregate([
  { $sample: { size: 3 } }
])
// Could be _id 5, 1, 7 — non-deterministic

// $sort + $limit — top 3 by rule (NOT random)
db.users.aggregate([
  { $sort: { name: 1 } },
  { $limit: 3 }
])
// First 3 alphabetically: ahn, annT, dave123

// Use $sample when you need randomness
// Use $sort + $limit for ranked top-N

How It Works

Beginners often confuse $sample with $limit. Remember: only $sample introduces randomness. For “top 3 by score,” use $sort + $limit.

Example 5 — QA spot-check pipeline (sample + project)

mongosh
// Random 2 gold-tier users for manual QA review
db.users.aggregate([
  { $match: { tier: "gold", active: true } },
  { $sample: { size: 2 } },
  {
    $project: {
      _id: 0,
      name: 1,
      tier: 1,
      reviewNote: { $literal: "QA spot check" },
      sampledAt: "$$NOW"
    }
  }
])

// 3 gold active users in pool → 2 chosen randomly
// reviewNote + sampledAt added for audit trail
// To freeze cohort: append { $out: "qa_cohort" }

How It Works

Production teams use $sample for spot audits without exporting full tables. Persist with $out when the same random cohort must be re-reviewed later.

🧠 How $sample Works

1

Input pool

Documents arrive from the collection (if first stage) or from prior stages like $match.

Pool
2

Strategy chosen

MongoDB picks fast pseudo-random cursor or full read + random sort based on stage position, size, and collection count.

Plan
3

N documents picked

Exactly size documents selected at random—or all available if fewer exist.

Select
=

Random subset

Downstream stages or the client receive an unpredictable sample—ideal for previews and audits.

📝 Notes

  • size must be an integer ≥ 1.
  • Results are non-deterministic—re-running the pipeline may return different documents.
  • For repeatable cohorts, follow $sample with $out or $merge.
  • On views, $sample is never the first stage—expect slower sampling.
  • On sharded clusters, each shard samples independently before merge.
  • Previous topic: $replaceWith. Next: $search.

Conclusion

$sample is the pipeline’s random picker: set size, place it early for performance, and combine with $match when the sample must come from a filtered pool.

Do not confuse it with $limit—only $sample shuffles the deck. Next: $search for full-text search in aggregation pipelines.

💡 Best Practices

✅ Do

  • Put $sample first when sampling an entire collection for speed
  • Use $match before $sample to define the eligible pool
  • Keep size small relative to collection count when possible
  • Persist with $out when the same random cohort must be reused
  • Use for QA spot checks and development data previews

❌ Don’t

  • Expect identical results on every pipeline run
  • Use $sample when you need top-N ranked rows—use $sort + $limit
  • Request huge size values on large collections without filtering first
  • Assume optimized sampling on views—it always uses the slower path
  • Confuse $sample with $limit for pagination

Key Takeaways

Knowledge Unlocked

Five things to remember about $sample

Use these points whenever you need random documents in a pipeline.

5
Core concepts
02

First stage

Fast path.

Perf
🔍 03

$match first

Filter pool.

Pattern
📈 04

vs $limit

Not same.

Compare
🔄 05

Varies

Re-run differs.

Behavior

❓ Frequently Asked Questions

$sample randomly selects a specified number of documents (size: N) from the documents entering the stage. Use it to pull random subsets for testing, spot checks, analytics previews, or machine-learning train/test splits inside aggregation pipelines.
$limit returns the first N documents in the current pipeline order—deterministic. $sample returns N randomly chosen documents—non-deterministic across runs. Use $limit after $sort for top-N; use $sample when you need randomness.
As the first stage when sampling directly from a collection and N is less than about 5% of total documents (with 100+ docs), MongoDB can use a fast pseudo-random cursor. Otherwise it reads all input documents and performs a random sort—which is slower on large sets.
$sample returns all available documents—never more than exist. If the collection has 7 documents and size is 10, you get 7 documents back.
Yes, but on a view $sample is appended after the view's pipeline—it is never the first stage. That means a collection scan and random sort path, not the optimized pseudo-random cursor.
Conceptually similar—both pick random rows. MongoDB's $sample is an aggregation stage with size: N syntax. For repeatable samples, run $sample once and $out results; random output changes on each pipeline execution.
Did you know?

When $sample is the first stage and size is less than about 5% of a collection with 100+ documents, MongoDB uses a pseudo-random cursor instead of sorting the entire collection—making small random previews very fast even on millions of documents. See the official $sample docs.

Continue the Stages Series

Sample randomly with $sample, then search with $search.

Next: $search →

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.

5 people found this page helpful