MongoDB $stdDevSamp Accumulator

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

What You’ll Learn

The $stdDevSamp accumulator measures sample standard deviation in each $group bucket—how far numeric values spread when your data is a sample meant to represent a larger population.

01

Sample spread

N−1 divisor formula.

02

Simple syntax

{ $stdDevSamp: "$field" }

03

vs $stdDevPop

Sample vs population.

04

+ $avg

Mean and spread together.

05

One value → null

Needs at least two points.

06

With $sample

Random subset analysis.

Definition and Usage

$stdDevSamp is a MongoDB accumulator used in the $group stage. For each group, it evaluates a numeric expression on every document and returns the sample standard deviation—spread calculated with Bessel’s correction (divide variance by N−1).

💡
Beginner tip

Ask: “Is this group all the data I care about, or just a slice of something bigger?” All the data → $stdDevPop. A slice meant to represent more → $stdDevSamp.

Use $stdDevSamp after $sample, for survey subsets, or when each group holds partial readings you want to extrapolate. When the group is the complete dataset, use $stdDevPop instead.

📝 Syntax

$stdDevSamp takes one expression inside $group:

mongosh
{
  $group: {
    _id: <expression>,
    <outputField>: { $stdDevSamp: <expression> }
  }
}

Syntax Rules

  • Stage — primary use as accumulator in $group (also $bucket, windows).
  • Expression — field path like "$age" or a numeric formula.
  • Output — a double standard deviation value, or null if insufficient numeric inputs.
  • Sample formula — divides variance by N−1, not N.
  • Non-numeric — null, missing, strings, booleans, and objects are ignored.
  • Single value — one numeric document returns null (cannot divide by zero).
mongosh
db.users.aggregate([
  { $sample: { size: 100 } },
  {
    $group: {
      _id: null,
      ageStdDev: { $stdDevSamp: "$age" }
    }
  }
]);

⚡ Quick Reference

QuestionAnswer
Stage$group accumulator
Syntax{ $stdDevSamp: <expression> }
MeasuresSample standard deviation (spread estimate)
vs $stdDevPopSample divides by N−1; population by N
One numeric valueReturns null
All non-numericReturns null
Per category
{ _id: "$quiz",
  std: { $stdDevSamp: "$score" } }

Sample spread per quiz

After $sample
{ $sample: { size: 100 } }
{ $group: { _id: null,
  std: { $stdDevSamp: "$age" } } }

Random subset stats

Pop + sample
pop:  { $stdDevPop: "$score" }
samp: { $stdDevSamp: "$score" }

Compare both formulas

Round output
{ $round: ["$stdDev", 2] }

In $project stage

🧰 Parameters

$stdDevSamp accepts one expression inside $group:

expression Required

Numeric value evaluated per document in the group. Non-numeric results are skipped from the calculation.

{ $stdDevSamp: "$score" }
{ $stdDevSamp: "$age" }
_id Group key

Defines buckets. Each group gets its own sample standard deviation based only on documents in that bucket.

_id: "$quiz"
return type Double | null

MongoDB returns the result as a double. Returns null when fewer than two numeric values exist.

9.848857801796104
minimum count Edge case

Requires at least two numeric values. One value → null. Zero values → null.

// N >= 2 required

Examples Gallery

Quiz scores and user ages—calculate sample spread per group, compare with $stdDevPop, and use after $sample.

📚 Getting Started

Insert quiz scores and compute sample standard deviation per quiz.

Example 1 — Sample users collection

mongosh
db.users.insertMany([
  { _id: 1, name: "dave123", quiz: 1, score: 85 },
  { _id: 2, name: "dave2",   quiz: 1, score: 90 },
  { _id: 3, name: "ahn",     quiz: 1, score: 71 },
  { _id: 4, name: "li",      quiz: 2, score: 96 },
  { _id: 5, name: "annT",    quiz: 2, score: 77 },
  { _id: 6, name: "ty",      quiz: 2, score: 82 }
]);

How It Works

Quiz 1 scores 85, 90, 71 have mean 82. Sample std dev ≈ 9.85 (larger than population std dev ≈ 8.04 for the same three values).

Example 2 — Sample standard deviation per quiz

mongosh
db.users.aggregate([
  {
    $group: {
      _id: "$quiz",
      stdDevSamp: { $stdDevSamp: "$score" },
      avgScore:   { $avg: "$score" },
      count:      { $sum: 1 }
    }
  },
  { $sort: { _id: 1 } }
]);

/* Quiz 1 (scores 85, 90, 71):
   avgScore: 82, stdDevSamp: ~9.85, count: 3
   Quiz 2 (scores 96, 77, 82):
   avgScore: 85, stdDevSamp: ~9.85, count: 3 */
*/

How It Works

MongoDB sums squared deviations from the mean and divides by N−1 (2 for three scores), then takes the square root.

📈 Practical Patterns

Compare formulas, analyze age samples, and round for dashboards.

Example 3 — $stdDevSamp vs $stdDevPop

mongosh
db.users.aggregate([
  { $match: { quiz: 1 } },
  {
    $group: {
      _id: "$quiz",
      stdDevPop:  { $stdDevPop: "$score" },
      stdDevSamp: { $stdDevSamp: "$score" }
    }
  }
]);

/* Quiz 1 scores: 85, 90, 71
   stdDevPop:  ~8.04  (divide by N=3)
   stdDevSamp: ~9.85  (divide by N−1=2) */
*/

How It Works

Sample std dev is always ≥ population std dev for the same data (when N ≥ 2). The gap widens with smaller sample sizes.

Example 4 — Sample std dev of user ages (MongoDB docs pattern)

mongosh
db.profiles.insertMany([
  { _id: 0, username: "user0", age: 20 },
  { _id: 1, username: "user1", age: 42 },
  { _id: 2, username: "user2", age: 28 }
]);

db.profiles.aggregate([
  {
    $group: {
      _id: null,
      ageStdDev: { $stdDevSamp: "$age" },
      avgAge:    { $avg: "$age" }
    }
  }
]);

/* ages 20, 42, 28 → avgAge: 30
   ageStdDev: ~11.14 (sample, N−1=2) */
*/

How It Works

In production, pair $sample before $group to analyze a random subset of a large collection—then $stdDevSamp estimates population spread from that sample.

Example 5 — Single value returns null; round multi-value results

mongosh
db.scores.insertMany([
  { class: "10A", score: 95 },
  { class: "10B", score: 78 },
  { class: "10B", score: 82 }
]);

db.scores.aggregate([
  {
    $group: {
      _id: "$class",
      stdDevSamp: { $stdDevSamp: "$score" },
      count:      { $sum: 1 }
    }
  },
  {
    $project: {
      _id: 1,
      count: 1,
      stdDevSamp: {
        $round: ["$stdDevSamp", 2]
      }
    }
  },
  { $sort: { _id: 1 } }
]);

/* 10A (one score)  → stdDevSamp: null
   10B (two scores) → stdDevSamp: 2.83 (rounded) */
*/

How It Works

Unlike $stdDevPop (which returns 0 for one value), $stdDevSamp returns null—you need at least two numeric points for a sample spread.

🧠 How $stdDevSamp Works

1

Documents bucketed

$group assigns each document to a bucket via _id.

Group
2

Numeric values collected

Each document’s expression is evaluated; non-numeric values are skipped.

Collect
3

Sample variance computed

MongoDB finds the mean, sums squared deviations, and divides by N−1.

Variance
=

Std dev returned

Square root of sample variance—or null if fewer than two numeric values exist.

📝 Notes

  • $stdDevSamp uses the sample formula (divide variance by N−1)—Bessel’s correction.
  • At least two numeric values are required; one value returns null (unlike $stdDevPop which returns 0).
  • Non-numeric values are ignored—same behavior as $avg and $sum.
  • In $group, an expression that resolves to an array is treated as non-numeric.
  • Sample std dev is typically slightly larger than population std dev for the same dataset.
  • Previous topic: $stdDevPop. Next: $sum.

Conclusion

$stdDevSamp estimates spread when your grouped data is a sample, not the full population. Use it with $sample, survey subsets, or any partial dataset you want to generalize from.

When the group contains every value you care about, use $stdDevPop instead. Next: $sum for totaling numeric values per group.

💡 Best Practices

✅ Do

  • Use $stdDevSamp when data is a sample of a larger population
  • Pair with $sample for random-subset statistical analysis
  • Report $sum: 1 (count) alongside std dev for context
  • Compare $stdDevPop and $stdDevSamp side by side when teaching or validating
  • Round with $round for dashboard-friendly output

❌ Don’t

  • Use $stdDevSamp on complete census data—use $stdDevPop
  • Expect a result from groups with only one numeric value—it returns null
  • Confuse sample (N−1) and population (N) formulas
  • Compare std dev across groups with very different counts without showing N
  • Pass array fields directly in $group—they are ignored as non-numeric

Key Takeaways

Knowledge Unlocked

Five things to remember about $stdDevSamp

Use these points when estimating spread from sample data in $group.

5
Core concepts
📝 02

Simple syntax

{ $stdDevSamp: "$field" }

Syntax
📈 03

vs $stdDevPop

Sample vs population.

Compare
🎯 04

≥ 2 values

One → null.

Edge case
💲 05

+ $sample

Random subsets.

Pattern

❓ Frequently Asked Questions

$stdDevSamp calculates the sample standard deviation of numeric values in each $group bucket. It estimates how spread out values are when your grouped data is a sample meant to represent a larger population.
Inside $group: { spread: { $stdDevSamp: "$score" } }. It also works in $project, $addFields, and window stages—but this tutorial focuses on the $group accumulator.
$stdDevSamp divides variance by N−1 (sample formula). $stdDevPop divides by N (population formula). Use $stdDevSamp when inferring about a bigger population from a subset.
Non-numeric values—including null, missing fields, strings, and objects—are ignored. If no numeric values exist in a group, $stdDevSamp returns null.
$stdDevSamp returns null. Sample standard deviation requires at least two data points (divisor N−1 would be zero with one value).
Choose $stdDevSamp when your group is a random subset (e.g. after $sample) or partial data you want to generalize from. Choose $stdDevPop when the group is the complete population you care about.
Did you know?

For quiz 1 scores 85, 90, and 71, $stdDevPop returns ~8.04 while $stdDevSamp returns ~9.85—the sample formula is slightly higher because dividing by N−1 instead of N compensates for using a subset to estimate a larger population. See the official $stdDevSamp docs.

Continue the Accumulators Series

Estimate sample spread with $stdDevSamp, then learn $sum for totaling values per group.

Next: $sum →

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