MongoDB $firstN Accumulator

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

What You’ll Learn

The $firstN accumulator collects the first N input values from each $group bucket—ideal for the first three orders per customer, earliest events, or top-N lists when you define order with $sort.

01

N values per group

Array of leading records.

02

input + n

Two required properties.

03

Needs $sort

Order before $group matters.

04

vs $first

Many values vs one value.

05

vs $topN

Pre-sorted vs in-group rank.

06

Array operator too

Slice arrays in $project.

Definition and Usage

$firstN is a MongoDB accumulator used in the $group stage. For each group, it evaluates an input expression on the first n documents (in pipeline order) and returns those values as an array.

💡
Beginner tip

$firstN does not sort documents. It simply takes the first N docs that reach each group. Add $sort before $group when you need earliest dates, highest scores first, or any predictable ordering.

Use $firstN when the stream is already ordered. If you need MongoDB to rank inside the group, consider $topN instead. For a single leading value, use $first.

📝 Syntax

As a $group accumulator, $firstN requires input and n:

mongosh
{
  $group: {
    _id: <expression>,
    <field>: {
      $firstN: {
        input: <expression>,
        n: <positive integer expression>
      }
    }
  }
}

Syntax Rules

  • input — expression evaluated per document: field path, projection object, or array like ["$playerId", "$score"].
  • n — positive integer; how many first documents to collect. Can be constant or depend on _id.
  • Array result — unlike $first, the output is always an array (up to n elements).
  • Fewer than N — groups with fewer documents return all available elements.
  • Null / missing — missing fields become null and are kept in the array.
  • Array operator — also works in $project / $addFields to take the first N elements from an array field.
mongosh
db.gamescores.aggregate([
  { $sort: { gameId: 1, score: -1 } },
  {
    $group: {
      _id: "$gameId",
      topThree: {
        $firstN: {
          input: { player: "$playerId", score: "$score" },
          n: 3
        }
      }
    }
  }
]);

⚡ Quick Reference

QuestionAnswer
Stage$group accumulator (also array operator)
Required keysinput, n
ReturnsArray of up to N values per group
Earliest N pattern$sort: { date: 1 } then $firstN
Group smaller than NReturns all documents in the group
MongoDB version5.2+ (accumulator)
First 3
n: 3

Collect three leading values

Field input
input: "$score"

Scalar per document

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

Pair values per element

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

n from group key

🧰 Parameters

The $firstN accumulator object has two required properties:

input Required

Expression evaluated on each of the first n documents in the group. Can be a field path, object projection, or array of fields.

input: "$score"
input: { player: "$playerId", score: "$score" }
n Required

Positive integer limiting how many documents contribute to the result. Can be a constant or an expression tied to the group _id.

n: 5
n: { $cond: [ …, 1, 3 ] }
$sort Prerequisite

Preceding stage that defines document order. Without it, “first N” follows arbitrary processing order.

{ $sort: { gameId: 1, score: -1 } }
array operator Alternate use

In $project or $addFields, slice the first N elements from an array field on each document (not per-group accumulation).

{ $firstN: { n: 3, input: "$scores" } }

Examples Gallery

Game scores grouped by gameId—collect the first three player records per game and see how $sort changes results.

📚 Getting Started

Sample game scores and the core $firstN 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 with four players each—enough data to verify first-3 arrays per group.

Example 2 — First three players in one game

mongosh
db.gamescores.aggregate([
  { $match: { gameId: "G1" } },
  {
    $group: {
      _id: "$gameId",
      firstThree: {
        $firstN: {
          input: ["$playerId", "$score"],
          n: 3
        }
      }
    }
  }
]);

/* Result (insertion order):
[
  {
    _id: "G1",
    firstThree: [
      ["PlayerA", 31],
      ["PlayerB", 33],
      ["PlayerC", 99]
    ]
  }
]
*/

How It Works

Without $sort, “first” means whatever order documents were inserted or scanned—fine for demos, risky in production.

📈 Practical Patterns

Control order with $sort, compare with $first, and vary n.

Example 3 — Top three scores per game (with $sort)

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

/* G1 topThree (highest scores first in stream):
   [ ["PlayerC", 99], ["PlayerB", 33], ["PlayerA", 31] ]
   G2: [ ["PlayerD", 80], ["PlayerC", 66], ["PlayerB", 14] ] */
*/

How It Works

Global $sort: { score: -1 } puts highest scores first. Within each game group, the first three documents encountered are the top scorers.

Example 4 — $firstN vs $first

mongosh
db.gamescores.aggregate([
  { $sort: { gameId: 1, score: -1 } },
  {
    $group: {
      _id: "$gameId",
      topScore: {
        $first: "$score"
      },
      topThreeScores: {
        $firstN: {
          input: "$score",
          n: 3
        }
      }
    }
  }
]);

/* G1:
   topScore: 99
   topThreeScores: [99, 33, 31] */
*/

How It Works

Both read from the same sorted order. $first grabs one value; $firstN builds a list from the first N documents.

Example 5 — Dynamic n based on group key

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

mongosh
db.gamescores.aggregate([
  {
    $group: {
      _id: { gameId: "$gameId" },
      scores: {
        $firstN: {
          input: "$score",
          n: {
            $cond: {
              if: { $eq: ["$gameId", "G2"] },
              then: 1,
              else: 3
            }
          }
        }
      }
    }
  },
  { $sort: { "_id.gameId": 1 } }
]);

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

How It Works

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

🧠 How $firstN Works

1

Documents sorted

$sort (recommended) defines the order documents flow into $group.

Sort
2

Documents bucketed

$group assigns each document to a bucket via _id.

Group
3

First N captured

For each bucket, input is evaluated on the leading n documents only.

Collect
=

Array returned

Up to n elements per group—each shaped by the input expression.

📝 Notes

  • Always $sort first when “first N” must mean earliest, top-ranked, or cheapest.
  • $firstN requires MongoDB 5.2+ as a $group accumulator.
  • Result is an array per group; use $first for a single scalar.
  • Groups with fewer than n documents return all available elements.
  • As an array operator, $firstN slices array fields in $project / $addFields—separate from group accumulation.
  • For in-group ranking without a prior $sort, prefer $topN or $bottomN.
  • Previous topic: $first. Next: $last.

Conclusion

$firstN extends $first to collect several leading values per group. Pair it with $sort, set input and n, and you get clean top-N or earliest-N reports without manual $push + $slice workarounds.

Need only one value? Use $first. Need ranking inside the group? Try $topN. Next up: $last for the trailing document value.

💡 Best Practices

✅ Do

  • Add $sort before $group whenever order defines “first”
  • Include tie-break sort keys (_id, name) for stable arrays
  • Use tuple input: ["$player", "$score"] for compact leaderboard rows
  • Test groups smaller than n to confirm array length behavior
  • Use the array-operator form to slice existing array fields in $addFields

❌ Don’t

  • Confuse $firstN with $first (array vs single value)
  • Skip $sort and expect consistent top-N or earliest-N results
  • Use $firstN when $topN in-group ranking is clearer
  • Assume null/missing values are skipped—they are included in the array
  • Deploy on MongoDB versions before 5.2 without a fallback pipeline

Key Takeaways

Knowledge Unlocked

Five things to remember about $firstN

Use these points when building first-N lists inside $group.

5
Core concepts
📄 02

input + n

Two required keys.

Syntax
📅 03

$sort first

Define what first means.

Pattern
👤 04

vs $first

List vs single value.

Compare
📈 05

vs $topN

Pre-sort vs in-group rank.

Choose

❓ Frequently Asked Questions

$firstN returns an array of the first N input values from each $group bucket—based on the order documents arrive at $group. Use it for the first three orders per customer, opening prices, or earliest N events when you control order with $sort.
Inside $group: { firstThree: { $firstN: { input: "$score", n: 3 } } }. Both input and n are required. It also works as an array operator in $project and $addFields to slice the first N elements from an array field.
Yes, whenever order matters. $firstN collects the first N documents as they enter each group—it does not sort for you. Add $sort before $group so first means earliest, cheapest, or highest per your rules.
$first returns one value from the first document. $firstN returns an array of up to N values from the first N documents. Use $first for a single field; use $firstN for a list of leading records.
$firstN assumes documents are already ordered (usually via $sort). $topN sorts inside $group with sortBy and picks the top N. Use $firstN when you sorted upstream; use $topN when ranking happens in the accumulator.
$firstN returns all available elements—never more than exist in the group. A group with two documents and n: 3 yields an array of two items.
Did you know?

$firstN doubles as an array operator—you can slice the first three elements from an array field in $addFields without grouping at all. As a group accumulator, it replaced older $push + $slice recipes for top-N lists. See the official $firstN docs.

Continue the Accumulators Series

Build first-N arrays with $firstN, then learn $last for the trailing value per group.

Next: $last →

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