MongoDB
Database
Query
Array
Programming

MongoDB - Query on the last element of an array?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When people ask how to query the last element of a MongoDB array, they usually mean one of two things: either project the last element in the result, or filter documents based on what the last element is. Those are related tasks, but MongoDB handles them differently depending on whether you are using a simple find projection or an aggregation pipeline.

Example Data

Assume documents like this:

javascript
1db.orders.insertMany([
2  {
3    _id: 1,
4    statusHistory: ["created", "paid", "shipped"]
5  },
6  {
7    _id: 2,
8    statusHistory: ["created", "cancelled"]
9  }
10])

Here, the last array element is the current status.

Project The Last Element

If you want to return the last array element in the output, aggregation is the clearest option.

javascript
1db.orders.aggregate([
2  {
3    $project: {
4      _id: 1,
5      lastStatus: { $arrayElemAt: ["$statusHistory", -1] }
6    }
7  }
8])

This produces a field called lastStatus with the final element from the array.

Using $arrayElemAt with -1 is concise and avoids manual size arithmetic.

Filter Documents By Their Last Element

If you want only documents whose last element matches a value, use $expr so the comparison can be computed from the document itself.

javascript
1db.orders.find({
2  $expr: {
3    $eq: [
4      { $arrayElemAt: ["$statusHistory", -1] },
5      "shipped"
6    ]
7  }
8})

This returns only documents where the last status is shipped.

Alternative: $slice In Projection

If you want a one-element array containing the last item, $slice is also useful.

javascript
1db.orders.find(
2  {},
3  {
4    statusHistory: { $slice: -1 }
5  }
6)

This is a projection tool, not a filter. It returns the final array element wrapped inside a one-element array.

That can be handy when the consuming code expects an array shape rather than a scalar value.

Working With Arrays Of Objects

The same pattern works for arrays of embedded documents.

javascript
1db.customers.aggregate([
2  {
3    $project: {
4      _id: 1,
5      lastOrder: { $arrayElemAt: ["$orders", -1] }
6    }
7  }
8])

If orders is an array of objects, lastOrder becomes the last embedded document.

To filter by a field inside the last embedded document, combine $arrayElemAt with a field expression in aggregation, or restructure the array logic with $let or $project first.

When A Schema Change Is Better

If you query the last element constantly, it may be better to store that information separately rather than recomputing it on every read.

For example, maintain:

  • 'statusHistory for the audit trail'
  • 'currentStatus as a top-level field'

That design gives you simpler queries and more index-friendly access patterns.

Empty Arrays Need Care

If the array can be empty, think about the behavior you want. Query expressions involving the last element may produce null or fail to match as expected when there is no element at all.

A defensive filter can add a size check.

javascript
1db.orders.find({
2  $expr: {
3    $and: [
4      { $gt: [{ $size: "$statusHistory" }, 0] },
5      {
6        $eq: [
7          { $arrayElemAt: ["$statusHistory", -1] },
8          "shipped"
9        ]
10      }
11    ]
12  }
13})

Common Pitfalls

A common mistake is using dot notation such as statusHistory.-1, which is not valid query syntax in the way people expect.

Another issue is confusing projection with filtering. $slice is useful for returning the last element, but it does not by itself filter documents by that value.

Developers also sometimes compute the last element on every query even though the application already conceptually tracks a current state. In that situation, a separate top-level field is often a better schema design.

Finally, remember to consider empty arrays. Last-element logic is easy when every document has data, but real collections often contain edge cases.

Summary

  • Use $arrayElemAt: ["$array", -1] when you want the last element directly.
  • Use aggregation or $expr when filtering by the last element's value.
  • Use $slice: -1 when you want the result as a one-element array in projection.
  • For arrays of objects, the same techniques work on embedded documents.
  • If last-element access is frequent, consider storing the current value separately for simpler queries.

Course illustration
Course illustration

All Rights Reserved.