MongoDB $range Operator

Beginner
⏱️ 8 min read
📚 Updated: Jul 2026
🎯 4 Examples
Array

What You’ll Learn

The $range operator generates an array of integers in sequence inside MongoDB aggregation pipelines. Use it to create index lists, month numbers, pagination slots, or any counted sequence without storing it in your data.

01

Number Sequence

Start to end array.

02

Start / End

Inclusive start, exclusive end.

03

Step Value

Skip by 2, -1, etc.

04

+ $unwind

One row per index.

05

Use Cases

Months, pages, loops.

06

+ $map

Indexed transforms.

Definition and Usage

In MongoDB’s aggregation framework, the $range operator returns an array of integers from a start value up to (but not including) an end value. For example, { $range: [0, 5] } produces [0, 1, 2, 3, 4], and { $range: [0, 10, 2] } produces [0, 2, 4, 6, 8].

This is especially useful when you need a sequence on the fly — calendar months, page numbers, retry counts, or array indexes — without pre-storing those values in documents.

💡
Beginner Tip

Think of $range like Python’s range(start, end, step) or JavaScript’s loop counter. The end is exclusive, so to get 1 through 5 use { $range: [1, 6] }.

📝 Syntax

The $range operator takes an array with two or three expressions:

mongosh
{ $range: [ <start>, <end>, <optional non-zero step> ] }

Syntax Rules

  • Start — inclusive; the first value in the output array.
  • End — exclusive; the sequence stops before this value.
  • Step — optional; defaults to 1. Must be non-zero.
  • Positive step: start must be less than end (e.g. [0, 5]).
  • Negative step: start must be greater than end (e.g. [5, 0, -1]).
  • Use inside $project, $addFields, $set, or nested in $map.

💡 Exclusive End & Common Patterns

{ $range: [0, 5] }[0, 1, 2, 3, 4] (5 is excluded)
{ $range: [1, 6] }[1, 2, 3, 4, 5] (values 1–5)
{ $range: [0, 10, 2] }[0, 2, 4, 6, 8] (step by 2)
{ $range: [5, 0, -1] }[5, 4, 3, 2, 1] (count down)

⚡ Quick Reference

QuestionAnswer
Operator typeAggregation expression operator (array generator)
Syntax{ $range: [ start, end, step? ] }
StartInclusive
EndExclusive
Default step1 (must not be zero)
Basic
{
  $range: [0, 5]
}

[0,1,2,3,4]

Step
{
  $range: [0, 10, 2]
}

Even numbers

Down
{
  $range: [5, 0, -1]
}

Countdown

Months
{
  $range: [1, 13]
}

Jan–Dec (1–12)

Examples Gallery

Generate basic sequences, use custom steps, unwind into rows, and build month calendars from a single config document.

📚 Basic Sequences

Create integer arrays with start and end values in $project.

Example 1 — Basic $range

Generate integers from 0 up to (but not including) 5:

mongosh
db.samples.aggregate([
  {
    $project: {
      sequence: { $range: [0, 5] }
    }
  }
])

// sequence: [0, 1, 2, 3, 4]

How It Works

Start 0 is included; end 5 is excluded. The default step is 1.

Example 2 — $range with a Step

Generate even numbers from 0 to 10:

mongosh
db.samples.aggregate([
  {
    $project: {
      evens: { $range: [0, 10, 2] }
    }
  }
])

// evens: [0, 2, 4, 6, 8]

How It Works

Each value increases by 2. The sequence stops before 10, so 8 is the last element.

📈 Practical Patterns

Unwind sequences into rows, generate months, and count down with negative steps.

Example 3 — $range with $unwind (Pagination Slots)

Create one document per page index from a config document:

mongosh
db.reports.aggregate([
  {
    $project: {
      reportName: 1,
      pageIndexes: { $range: [0, "$pageCount"] }
    }
  },
  { $unwind: "$pageIndexes" },
  {
    $project: {
      reportName: 1,
      page: { $add: [ "$pageIndexes", 1 ] }
    }
  }
])

// pageCount: 3 → pages 1, 2, 3

How It Works

$range builds [0, 1, 2] when pageCount is 3. $unwind splits into one row per index; $add shifts to 1-based page numbers for display.

Example 4 — Generate Month Numbers (1–12)

Build a calendar month list from a single config document:

mongosh
db.config.aggregate([
  {
    $project: {
      year: 1,
      months: { $range: [1, 13] }
    }
  },
  { $unwind: "$months" },
  {
    $project: {
      year: 1,
      month: "$months"
    }
  }
])

How It Works

Use end 13 to include month 12 (end is exclusive). $unwind produces 12 rows for reporting or joins.

Bonus — Countdown with Negative Step

Generate a descending sequence:

mongosh
db.samples.aggregate([
  {
    $project: {
      countdown: { $range: [5, 0, -1] }
    }
  }
])

// countdown: [5, 4, 3, 2, 1]

How It Works

When start > end, use a negative step. The end 0 is still exclusive, so the sequence stops at 1.

Bonus — $range Inside $map

Square each number in a generated sequence:

mongosh
db.samples.aggregate([
  {
    $project: {
      squares: {
        $map: {
          input: { $range: [1, 6] },
          as: "n",
          in: { $pow: [ "$$n", 2 ] }
        }
      }
    }
  }
])

// squares: [1, 4, 9, 16, 25]

How It Works

$range creates [1, 2, 3, 4, 5]; $map transforms each value. Pair $range with $map or $reduce for indexed logic.

🚀 Use Cases

  • Pagination indexes — generate page numbers from a total count field.
  • Calendar expansion — produce month or day sequences for reporting pipelines.
  • Test data — create indexed rows without inserting sequence documents.
  • Array iteration — feed $map or $reduce with a controlled index range.

🧠 How $range Works

1

MongoDB reads start, end, and step

The pipeline evaluates the three expressions — literals like 0 and 5, or field references like "$pageCount".

Input
2

$range builds the sequence

MongoDB increments (or decrements) by step from start until the next value would reach or pass end.

Generate
3

An integer array is returned

The array is stored in your projected field or passed to $unwind, $map, or $zip.

Output
=

On-demand sequences

Generate indexes, months, or loops without extra collection data.

Conclusion

The $range operator generates integer sequences in MongoDB aggregation pipelines. With inclusive start, exclusive end, and an optional step, it replaces many hand-built index arrays for pagination, calendars, and iteration.

Remember end is exclusive and step cannot be zero. Pair with $unwind for one-row-per-index output. Next in the series: $reduce.

💡 Best Practices

✅ Do

  • Remember end is exclusive (use 6 for values 1–5)
  • Use negative step when counting down
  • Pair with $unwind for one document per index
  • Pass field references for dynamic lengths: "$pageCount"
  • Combine with $map for indexed transformations

❌ Don’t

  • Use step 0 (MongoDB errors)
  • Assume end is inclusive
  • Use positive step when start > end (returns empty array)
  • Generate huge ranges that could exhaust memory
  • Confuse $range with query $gte/$lte filters

Key Takeaways

Knowledge Unlocked

Five things to remember about $range

Use these points when generating sequences in aggregation pipelines.

5
Core concepts
📝 02

Exclusive End

Stops before end.

Syntax
🛠 03

Step Default 1

Non-zero required.

Rule
🔀 04

+ $unwind

One row per index.

Pattern
📅 05

Months 1–12

[1, 13]

Use case

❓ Frequently Asked Questions

$range generates an array of integers in a sequence. You specify a start value (inclusive), an end value (exclusive), and an optional step. For example, { $range: [0, 5] } returns [0, 1, 2, 3, 4].
The syntax is { $range: [ <start>, <end>, <optional non-zero step> ] }. Start is inclusive, end is exclusive, and step defaults to 1 if omitted.
The end value is exclusive. { $range: [0, 5] } stops before 5 and returns [0, 1, 2, 3, 4]. To include 5, use end: 6.
Yes. Use a negative step when start is greater than end. For example, { $range: [5, 0, -1] } returns [5, 4, 3, 2, 1]. The step cannot be zero.
Generate a sequence in $project or $addFields, then $unwind the array to create one document per index. This is useful for pagination slots, repeated rows, or indexed iteration.

Continue the Operator Series

Move on to $reduce for folding arrays, or review $map for element-wise transforms.

Next: $reduce →

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