Discover how MongoDB's $first and $last can save you hours of tedious data searching!
Why $first and $last accumulators in MongoDB? - Purpose & Use Cases
Imagine you have a big list of customer orders sorted by date, and you want to find the very first and last order each customer made.
Doing this by hand means scanning through all orders for each customer, remembering the earliest and latest dates, and writing it down.
Manually checking each order is slow and tiring, especially when the list is huge.
It's easy to make mistakes, like missing an order or mixing up dates.
Also, updating the results when new orders come in means repeating the whole process again.
The $first and $last accumulators in MongoDB let you quickly grab the first and last items in a group during aggregation.
This means MongoDB does the hard work for you, scanning and picking the right records efficiently.
for each customer: earliest = None latest = None for order in orders: if order.customer == customer: if earliest is None or order.date < earliest: earliest = order.date if latest is None or order.date > latest: latest = order.date
[
{ $sort: { customer: 1, date: 1 } },
{ $group: {
_id: "$customer",
firstOrder: { $first: "$order" },
lastOrder: { $last: "$order" }
}
}
]You can instantly find the first and last records in any group, making data summaries and reports fast and reliable.
A store wants to know each customer's first and last purchase to send personalized offers and understand buying habits.
Manually finding first and last items is slow and error-prone.
$first and $last do this automatically during aggregation.
This saves time and ensures accurate results on large datasets.
Practice
$first accumulator do in a MongoDB aggregation pipeline?Solution
Step 1: Understand the role of $first
The$firstaccumulator returns the first value of a specified field from documents in a group.Step 2: Differentiate from other accumulators
Unlike$last, which returns the last value,$firstpicks the earliest value based on the document order.Final Answer:
It returns the first value of a specified field in each group. -> Option DQuick Check:
$first= first value [OK]
- Confusing $first with $last accumulator
- Thinking $first sorts documents automatically
- Assuming $first counts documents
$last in a MongoDB aggregation $group stage?Solution
Step 1: Identify correct accumulator usage
The$lastaccumulator must be used with a field path as a string, like"$item".Step 2: Check syntax correctness
{ $group: { _id: "$category", lastItem: { $last: "$item" } } } correctly uses$last: "$item"inside$group. Options A and C have syntax errors, and B uses$firstinstead of$last.Final Answer:
{ $group: { _id: "$category", lastItem: { $last: "$item" } } } -> Option CQuick Check:
Correct $last syntax = { $group: { _id: "$category", lastItem: { $last: "$item" } } } [OK]
- Omitting quotes around field name
- Using $first instead of $last by mistake
- Writing accumulator name incorrectly
sales with documents:{ "_id": 1, "product": "A", "date": "2023-01-01" },
{ "_id": 2, "product": "A", "date": "2023-01-05" },
{ "_id": 3, "product": "B", "date": "2023-01-02" }What will be the output of this aggregation?
[
{ $sort: { date: 1 } },
{ $group: { _id: "$product", firstSale: { $first: "$date" }, lastSale: { $last: "$date" } } }
]Solution
Step 1: Sort documents by date ascending
The $sort stage orders documents by date: A on 2023-01-01, B on 2023-01-02, A on 2023-01-05.Step 2: Group by product and apply $first and $last
For product A, firstSale is earliest date "2023-01-01", lastSale is latest date "2023-01-05". For B, both firstSale and lastSale are "2023-01-02".Final Answer:
[{ "_id": "A", "firstSale": "2023-01-01", "lastSale": "2023-01-05" }, { "_id": "B", "firstSale": "2023-01-02", "lastSale": "2023-01-02" }] -> Option BQuick Check:
Sorted + grouped $first/$last = [{ "_id": "A", "firstSale": "2023-01-01", "lastSale": "2023-01-05" }, { "_id": "B", "firstSale": "2023-01-02", "lastSale": "2023-01-02" }] [OK]
- Ignoring $sort stage before $group
- Mixing up $first and $last values
- Assuming $first/$last pick random values
$last values:db.orders.aggregate([
{ $group: { _id: "$customer", lastOrder: { $last: "$orderDate" } } }
])What is the most likely reason?
Solution
Step 1: Understand $last depends on document order
The$lastaccumulator returns the last value in the current document order within each group.Step 2: Identify missing $sort stage
Without sorting byorderDate, documents are in arbitrary order, so$lastmay not return the latest date.Final Answer:
You forgot to sort documents byorderDatebefore grouping. -> Option AQuick Check:
Missing $sort before $group causes wrong $last [OK]
- Assuming $last finds max value automatically
- Using $last without sorting documents
- Confusing $last with $max accumulator
events with documents:{ "user": "Alice", "timestamp": 100 },
{ "user": "Alice", "timestamp": 200 },
{ "user": "Bob", "timestamp": 150 },
{ "user": "Bob", "timestamp": 50 }You want to find each user's first and last event timestamps using the $first and $last accumulators. Which aggregation pipeline correctly achieves this?
Solution
Step 1: Sort events by timestamp ascending
Sorting bytimestamp: 1ensures earliest events come first for each user.Step 2: Group by user and use $first and $last
Using$firstand$lastafter sorting picks the earliest and latest timestamps correctly.Final Answer:
[ { $sort: { timestamp: 1 } }, { $group: { _id: "$user", firstEvent: { $first: "$timestamp" }, lastEvent: { $last: "$timestamp" } } } ] -> Option AQuick Check:
Sort ascending + $first/$last = [ { $sort: { timestamp: 1 } }, { $group: { _id: "$user", firstEvent: { $first: "$timestamp" }, lastEvent: { $last: "$timestamp" } } } ] [OK]
- Skipping $sort stage before $group
- Sorting descending when $first expects ascending
- Using $min/$max instead of $first/$last when order matters
Ready to prove it?
Pass the test and this pattern moves unknown
