MongoDB $topN Accumulator

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

What You’ll Learn

The $topN accumulator collects the N highest-ranked documents in each $group bucket—perfect for top-3 leaderboards, best-selling products, or latest orders when one record is not enough.

01

N docs per group

Array of top-ranked records.

02

n + sortBy + output

Three required properties.

03

Flexible output

Project fields or use arrays.

04

vs $top

Many records vs one record.

05

Short groups OK

Returns all docs if fewer than N.

06

MongoDB 5.2+

Part of $top/$bottom family.

Definition and Usage

$topN is a MongoDB accumulator used in the $group stage. It sorts documents within each group using sortBy, then returns the first N documents in that ordering as an array.

💡
Beginner tip

To get the three highest scores, use sortBy: { score: -1 } (descending). The biggest numbers sort first—PlayerC (99), PlayerB (33), PlayerA (31) fill the top three slots in game G1.

Choose $topN when dashboards need a leaderboard slice (top 5 sellers, 3 fastest response times). Use $top when only the single best record matters, or $bottomN for the bottom of the ranking.

📝 Syntax

$topN requires an object with n, sortBy, and output:

mongosh
{
  $group: {
    _id: <expression>,
    <field>: {
      $topN: {
        n: <positive integer expression>,
        sortBy: { <field>: <1 | -1>, ... },
        output: <expression> | { <field>: <expression>, ... }
      }
    }
  }
}

Syntax Rules

  • n — how many top documents to collect; must be a positive integer (constant or expression tied to _id).
  • sortBy — required; same format as $sort (1 = ascending, -1 = descending).
  • output — shapes each array element: projection object, scalar field, or array like ["$player", "$score"].
  • Array result — unlike $top, the accumulator value is always an array (possibly empty if the group is empty).
  • Fewer than N — if the group has 2 documents and n: 3, MongoDB returns 2 elements.
  • Version — available in MongoDB 5.2 and later.
mongosh
db.gamescores.aggregate([
  {
    $group: {
      _id: "$gameId",
      topThree: {
        $topN: {
          n: 3,
          sortBy: { score: -1 },
          output: { player: "$playerId", score: "$score" }
        }
      }
    }
  }
]);

⚡ Quick Reference

QuestionAnswer
Stage$group accumulator
Required keysn, sortBy, output
ReturnsArray of up to N items per group
Highest scores patternsortBy: { score: -1 }
Group smaller than NReturns all documents in the group
MongoDB version5.2+
Top 3
n: 3

Collect three top-ranked docs

Highest scores
sortBy: { score: -1 }

Desc → high scores at top

Tuple output
output: [
  "$playerId",
  "$score"
]

Pair values per element

Dynamic n
n: {
  $cond: [
    { $eq: ["$gameId", "G2"] },
    1, 3
  ]
}

n from group key

🧰 Parameters

The $topN object has three required properties:

n Required

Positive integer limiting how many top documents to return. Can be a constant (3) or an expression that depends on the group _id (e.g. $cond).

n: 5
n: { $cond: [ …, 1, 3 ] }
sortBy Required

Sort specification within each group before selecting the top N. Add secondary keys to break ties deterministically.

sortBy: { score: -1 }
sortBy: { score: -1, playerId: 1 }
output Required

Expression defining each element in the returned array—projection object, single field, or array of fields.

output: "$score"
output: { name: "$player", score: "$score" }
null / missing Edge case

Missing fields become null and are kept in results. With descending numeric sort, nulls tend to sort toward the bottom (outside the top N).

sortBy: { score: -1, playerId: 1 }

Examples Gallery

Game scores grouped by gameId—find the three highest scorers per game and explore advanced patterns.

📚 Getting Started

Sample game scores and the core $topN grouping pattern.

Example 1 — Sample gamescores collection

mongosh
db.gamescores.insertMany([
  { playerId: "PlayerA", gameId: "G1", score: 31 },
  { playerId: "PlayerB", gameId: "G1", score: 33 },
  { playerId: "PlayerC", gameId: "G1", score: 99 },
  { playerId: "PlayerD", gameId: "G1", score: 1 },
  { playerId: "PlayerA", gameId: "G2", score: 10 },
  { playerId: "PlayerB", gameId: "G2", score: 14 },
  { playerId: "PlayerC", gameId: "G2", score: 66 },
  { playerId: "PlayerD", gameId: "G2", score: 80 }
]);

How It Works

Two games (G1, G2) with four players each—enough data to verify top-3 results per group.

Example 2 — Three highest scores in one game

mongosh
db.gamescores.aggregate([
  { $match: { gameId: "G1" } },
  {
    $group: {
      _id: "$gameId",
      topThree: {
        $topN: {
          n: 3,
          sortBy: { score: -1 },
          output: ["$playerId", "$score"]
        }
      }
    }
  }
]);

/* Result:
[
  {
    _id: "G1",
    topThree: [
      ["PlayerC", 99],
      ["PlayerB", 33],
      ["PlayerA", 31]
    ]
  }
]
*/

How It Works

Descending sort lists 99 → 33 → 31 → 1. The top three positions are 99, 33, and 31—the three highest scores.

📈 Practical Patterns

Multiple games, compare with $top, and vary n per group.

Example 3 — Top 3 per game (all groups)

mongosh
db.gamescores.aggregate([
  {
    $group: {
      _id: "$gameId",
      topThree: {
        $topN: {
          n: 3,
          sortBy: { score: -1 },
          output: { player: "$playerId", score: "$score" }
        }
      }
    }
  },
  { $sort: { _id: 1 } }
]);

/* G1 top: PlayerC(99), PlayerB(33), PlayerA(31)
   G2 top: PlayerD(80), PlayerC(66), PlayerB(14) */
*/

How It Works

Each gameId group gets its own independent top-3 array—ideal for per-category leaderboards.

Example 4 — $topN vs $top

mongosh
db.gamescores.aggregate([
  { $match: { gameId: "G1" } },
  {
    $group: {
      _id: "$gameId",
      bestOnly: {
        $top: {
          sortBy: { score: -1 },
          output: ["$playerId", "$score"]
        }
      },
      bestThree: {
        $topN: {
          n: 3,
          sortBy: { score: -1 },
          output: ["$playerId", "$score"]
        }
      }
    }
  }
]);

/* bestOnly:  ["PlayerC", 99]              — one doc
   bestThree: [["PlayerC",99], …, ["PlayerA",31]] — array */
*/

How It Works

Both use the same sortBy in one $group when a report needs the absolute best and the top-k list together.

Example 5 — Dynamic n based on group key

Return 1 top score for game G2 but 3 for every other game:

mongosh
db.gamescores.aggregate([
  {
    $group: {
      _id: { gameId: "$gameId" },
      topScores: {
        $topN: {
          n: {
            $cond: {
              if: { $eq: ["$gameId", "G2"] },
              then: 1,
              else: 3
            }
          },
          sortBy: { score: -1 },
          output: "$score"
        }
      }
    }
  },
  { $sort: { "_id.gameId": 1 } }
]);

/* G1 → [99, 33, 31]
   G2 → [80] */
*/

How It Works

n can depend on _id—useful when different categories need different leaderboard sizes in one pipeline.

🧠 How $topN Works

1

Documents bucketed

$group assigns each document to a group via _id.

Group
2

Sorted within group

sortBy ranks every document inside each bucket.

Sort
3

First N selected

MongoDB takes the first n documents from that ordering (or all if fewer exist).

Pick N
=

Array returned

Each element is shaped by output—objects, scalars, or field tuples.

📝 Notes

  • $topN requires MongoDB 5.2+—verify server version before deploying.
  • All three keys—n, sortBy, output—are mandatory.
  • Result is an array per group; use $top when you need a single object.
  • Groups with fewer than n documents return all available top-ranked items.
  • Null and missing values are preserved; add tie-break sort keys for predictable ordering.
  • Large groups are subject to the 100 MB per-group aggregation memory limit.
  • Previous topic: $top. Next: Accumulators hub.

Conclusion

$topN answers “which N records sit at the high end of my ranking?” inside each group. Set n, define ranking with sortBy, and shape results with output.

Pair with $top for the single best record, or explore $firstN when input order matters instead of explicit in-group ranking.

💡 Best Practices

✅ Do

  • Document your sortBy choice—“top” follows sort order, not intuition alone
  • Use sortBy: { score: -1 } for highest numeric scores (MongoDB official pattern)
  • Add secondary sort keys (playerId, _id) to break ties
  • Put $match before $group to reduce data processed per bucket
  • Test with groups smaller than n to confirm array length behavior

❌ Don’t

  • Confuse $topN with $top (array vs single object)
  • Assume ascending sort always means “highest score”—use descending for max-first rankings
  • Expect $max or $maxN to return player names—they return values only
  • Use on MongoDB versions before 5.2 without a fallback pipeline
  • Forget the 100 MB per-group memory cap on very large buckets

Key Takeaways

Knowledge Unlocked

Five things to remember about $topN

Use these points when building top-k reports inside $group.

5
Core concepts
🔢 02

n key

How many to collect.

Syntax
🏆 03

sortBy

Defines top ranking.

Ranking
👤 04

vs $top

Many vs one record.

Compare
📄 05

5.2+

Check server version.

Version

❓ Frequently Asked Questions

$topN returns an array of the N documents ranked at the top of each $group bucket according to sortBy. Use it for top-3 scorers, highest-priced products, or latest N orders—when you need more than one best record.
Inside $group: { topThree: { $topN: { n: 3, sortBy: { score: -1 }, output: { name: "$player", score: "$score" } } } }. All three keys—n, sortBy, and output—are required.
$top returns exactly one top-ranked document (a single object). $topN returns up to N documents as an array. Use $top for the single best record; use $topN for a leaderboard or top-k list.
Use sortBy: { score: -1 } (descending)—highest scores sort first and land in the top N slots. For most recent records, use sortBy: { date: -1 }. Always match sortBy to your business definition of top.
$topN returns all documents in the group—never more than exist. If a class has only two students and n is 3, you get an array of two items.
$topN was added in MongoDB 5.2 alongside $top, $bottom, and $bottomN. On older servers, approximate with $sort + $group patterns (less efficient).
Did you know?

$topN can use a dynamic n expression based on the group _id—handy when one pipeline must return different leaderboard sizes per category. Before MongoDB 5.2, developers built top-k lists with $sort, $group, and $push + $slice. See the official $topN docs.

Continue the Accumulators Series

Master top-k arrays with $topN, then return to the accumulators hub for the full index.

Accumulators hub →

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