MongoDB $last Accumulator

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

What You’ll Learn

The $last accumulator picks the value from the last document in each $group bucket—ideal for latest sale dates, most recent orders, or closing prices when you control order with $sort.

01

Last per group

Value from the trailing doc.

02

Simple syntax

{ $last: "$field" }

03

Needs $sort

Order before $group matters.

04

vs $first

Last vs first in order.

05

vs $max

Last doc vs max value.

06

Null handling

Missing fields on last doc.

Definition and Usage

$last is a MongoDB accumulator used in $group (and related stages). It evaluates an expression on the last document that enters each group and returns that result.

💡
Beginner tip

$last does not sort documents itself. Without a preceding $sort, “last” means whatever order MongoDB happens to process—often unpredictable. Always sort first when you need the latest date, highest price in sequence, or most recent record.

Common pattern: $sort by date ascending, then $group with { lastSale: { $last: "$date" } } to get the most recent sale per product. Pair with $first for open/close date ranges. For ranked picks inside the group, consider $topN.

📝 Syntax

$last takes a single expression—the field or computed value to capture from the last document:

mongosh
{
  $group: {
    _id: <expression>,
    <field>: { $last: <expression> }
  }
}

Syntax Rules

  • One argument — pass any expression: field path, literal, or computed value.
  • Order matters — add $sort before $group to define what “last” means.
  • Scalar result — returns a single value per group (not an array), unless the expression itself is an array field.
  • Array fields — in $group, if the expression resolves to an array on the last doc, the entire array is returned (not the last element).
  • Missing values — if the last document lacks the field, $last returns null.
  • Stages — also works in $bucket, $bucketAuto, and as a window operator in $setWindowFields.
mongosh
db.sales.aggregate([
  { $sort: { item: 1, date: 1 } },
  {
    $group: {
      _id: "$item",
      lastSale: { $last: "$date" }
    }
  }
]);

⚡ Quick Reference

QuestionAnswer
Stage$group accumulator (also $bucket, windows)
Syntax{ $last: "$field" }
ReturnsOne value from the last doc per group
Latest date pattern$sort: { date: 1 } then $last: "$date"
Full last document{ $last: "$$ROOT" }
Requires $sort?Strongly recommended whenever order matters
Latest date
$sort: { date: 1 }
$last: "$date"

Sort asc → last = latest

Most recent first
$sort: { date: -1 }
$first: "$date"

Same result, different pattern

Full document
$last: "$$ROOT"

Entire last doc in group

Date range
firstDate: { $first: "$date" }
lastDate:  { $last: "$date" }

Open and close per group

🧰 Parameters

$last accepts one expression argument. These related concepts control behavior:

expression Required

Field path or expression evaluated on the last document in each group. Common: "$date", "$price", or "$$ROOT".

{ $last: "$date" }
{ $last: { $add: ["$price", "$tax"] } }
$sort Prerequisite

Preceding stage that defines document order before $group. Without it, “last” is not reliably the latest or highest-ranked record.

{ $sort: { item: 1, date: 1 } }
_id Group key

Standard $group bucket key—e.g. "$item" for per-product last sale dates.

_id: "$category"
missing / null Edge case

If the last document in a group lacks the target field, $last returns null. Sort order decides which document is “last.”

$sort before $group to control which doc is last

Examples Gallery

Sales records grouped by item—find the last sale date per product and explore ordering, comparisons, and edge cases.

📚 Getting Started

Sample sales data and the core $sort + $last pattern.

Example 1 — Sample sales collection

mongosh
db.sales.insertMany([
  { _id: 1, item: "abc", price: 10, quantity: 2,
    date: ISODate("2014-01-01T08:00:00Z") },
  { _id: 2, item: "jkl", price: 20, quantity: 1,
    date: ISODate("2014-02-03T09:00:00Z") },
  { _id: 3, item: "xyz", price: 5, quantity: 5,
    date: ISODate("2014-02-03T09:05:00Z") },
  { _id: 4, item: "abc", price: 10, quantity: 10,
    date: ISODate("2014-02-15T08:00:00Z") },
  { _id: 5, item: "xyz", price: 5, quantity: 10,
    date: ISODate("2014-02-15T09:05:00Z") },
  { _id: 6, item: "xyz", price: 5, quantity: 5,
    date: ISODate("2014-02-15T12:05:10Z") },
  { _id: 7, item: "xyz", price: 5, quantity: 10,
    date: ISODate("2014-02-15T14:12:12Z") }
]);

How It Works

Three products with multiple sale dates—xyz has four sales, making it ideal for verifying the latest date.

Example 2 — Last sale date per item

mongosh
db.sales.aggregate([
  { $sort: { item: 1, date: 1 } },
  {
    $group: {
      _id: "$item",
      lastSale: { $last: "$date" }
    }
  },
  { $sort: { _id: 1 } }
]);

/* Result:
[
  { _id: "abc", lastSale: ISODate("2014-02-15T08:00:00Z") },
  { _id: "jkl", lastSale: ISODate("2014-02-03T09:00:00Z") },
  { _id: "xyz", lastSale: ISODate("2014-02-15T14:12:12Z") }
]
*/

How It Works

Ascending sort by date puts the latest sale last in each item group—so $last captures the most recent date.

📈 Practical Patterns

Compare with $first, return full documents, and contrast with $max.

Example 3 — $first vs $last (date range per item)

mongosh
db.sales.aggregate([
  { $sort: { item: 1, date: 1 } },
  {
    $group: {
      _id: "$item",
      firstSale: { $first: "$date" },
      lastSale:  { $last: "$date" }
    }
  }
]);

/* xyz example:
   firstSale: 2014-02-03T09:05:00Z
   lastSale:  2014-02-15T14:12:12Z */
*/

How It Works

With the same ascending sort, $first and $last bookend each group—perfect for active date-range reports.

Example 4 — Return the full last document with $$ROOT

mongosh
db.sales.aggregate([
  { $sort: { item: 1, date: 1 } },
  {
    $group: {
      _id: "$item",
      lastOrder: { $last: "$$ROOT" }
    }
  }
]);

// lastOrder for xyz includes _id: 7, quantity: 10,
// and the latest date fields

How It Works

$$ROOT preserves the entire last document—useful when downstream stages need price, quantity, and date from the most recent sale.

Example 5 — $last vs $max

$max scans all documents; $last reads only the final document in sort order:

mongosh
db.sales.insertMany([
  { item: "widget", price: 50, date: ISODate("2024-03-01") },
  { item: "widget", price: 99, date: ISODate("2024-03-15") },
  { item: "widget", price: 75, date: ISODate("2024-03-20") }
]);

db.sales.aggregate([
  { $sort: { item: 1, date: 1 } },
  {
    $group: {
      _id: "$item",
      maxPrice:     { $max: "$price" },
      lastDocPrice: { $last: "$price" }
    }
  }
]);

/* maxPrice: 99 (highest in group)
   lastDocPrice: 75 (price on latest date, Mar 20) */
*/

How It Works

Use $max for the highest value anywhere in the group. Use $last when you need the value tied to the most recent (or last-sorted) record.

🧠 How $last 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

Last doc captured

Each new document overwrites the accumulator—only the final one in the group remains.

Capture
=

Value returned

One result per group—the expression value from that last document.

📝 Notes

  • Always $sort first when “last” must mean latest, most recent, or last in your ranking.
  • $last is order-dependent; it does not scan for max/latest across unordered groups.
  • $sort: { date: -1 } + $first is equivalent to $sort: { date: 1 } + $last for date fields.
  • Array fields return the whole array from the last document in $group, not the last array element.
  • Documents missing the grouped field still form a group with _id: null.
  • Previous topic: $firstN. Next: $lastN.

Conclusion

$last is the straightforward way to grab a value from the trailing document in each $group bucket. Pair it with $sort so “last” matches your business meaning—latest sale, most recent status, closing price.

Combine with $first for date ranges, or move to $lastN when you need several trailing documents per group.

💡 Best Practices

✅ Do

  • Add $sort immediately before $group when order matters
  • Include tie-break sort keys (_id, name) for stable last-document picks
  • Use $first + $last together for per-group time ranges
  • Use $$ROOT when downstream stages need the full last record
  • Put $match before $sort to reduce documents sorted

❌ Don’t

  • Assume $last returns the maximum value—it follows document order
  • Skip $sort and expect consistent “latest” results
  • Confuse $last with $lastN (one value vs array of N)
  • Expect $last to skip null on earlier documents—it only reads the last doc
  • Use $last for ranked picks when $top/$bottom fit better

Key Takeaways

Knowledge Unlocked

Five things to remember about $last

Use these points when capturing trailing values inside $group.

5
Core concepts
📅 02

$sort first

Define what last means.

Pattern
🔄 03

vs $first

Range endpoints.

Compare
📈 04

vs $max

Last doc vs peak value.

Compare
⚠️ 05

Null on miss

Last doc missing field.

Edge case

❓ Frequently Asked Questions

$last returns the value of an expression from the last document in each $group bucket—based on the order documents arrive at $group. Use it for latest dates, most recent order IDs, or closing prices per category.
Yes, in almost every real pipeline. $last does not sort for you—it takes whatever document is last in the current order. Add a $sort stage before $group so last means what you expect (e.g. latest date).
$last reads the final document in each group; $first reads the leading one. With $sort: { date: 1 }, $first gives the earliest date and $last gives the latest.
$max returns the largest numeric value across all documents in a group. $last returns a field from the last document in pipeline order—they can differ if the highest value is not on the last document.
$last returns null when the expression resolves to a missing field on that last document. It does not fall back to earlier documents in the group.
As an accumulator in $group, $bucket, and $bucketAuto. It is also a window operator in $setWindowFields (MongoDB 5.0+) with sortBy on the window.
Did you know?

Sorting by date descending and using $first gives the same result as sorting ascending and using $last—pick whichever reads clearer in your pipeline. See the official $last docs.

Continue the Accumulators Series

Capture single trailing values with $last, then learn $lastN for the last N documents per group.

Next: $lastN →

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