MongoDB $substr Operator

Beginner
5 min read
Updated: Oct 2026
3 examples
Live preview

What Is $substr?

$substr is a MongoDB aggregation expression that returns a substring starting at a zero-based index for a given length. It is deprecated since 3.4 and is an alias for $substrBytes. Prefer $substrBytes or $substrCP in new code.

Remember
$substr ≈ $substrBytes (legacy alias)

{ $substr: [ <string>, <start>, <length> ] }

"13Q1" + start 0, length 2 → "13"
"13Q1" + start 2, length -1 → "Q1"  (rest of string)

negative start → ""
ASCII-safe; for Unicode chars prefer $substrCP
UsePrefer
Legacy / ASCII substring$substr (or $substrBytes)
Character-safe Unicode slice$substrCP
Measure length first$strLenBytes / $strLenCP
Split by delimiter$split

How to Use $substr in MongoDB

Pass the string, a start index, and a length (or -1 for the remainder).

  1. Choose an expression stage ($addFields or $project).
  2. Pass the string expression as the first argument.
  3. Set start (0-based). Negative start returns "".
  4. Set length, or use -1 to take everything from start to the end.
PieceRequired?Role
StringYesSource text (field or literal)
StartYesZero-based index (negative → "")
LengthYesHow many units to take (-1 = rest of string)

Pseudocode

Pseudocode
for each document:
    s = evaluate(string)
    start = evaluate(startIndex)
    len = evaluate(length)
    if start < 0:
        result = ""
    else if len < 0:
        result = s from start to end
    else:
        result = s from start for len units
    emit { ..., field: result }

Cheat Sheet

Keep these facts handy while extracting substrings.

TopicDetail
TypeAggregation expression (not a find filter)
Syntax{ $substr: [ <string>, <start>, <length> ] }
StatusDeprecated alias of $substrBytes (since 3.4)
Negative startReturns ""
Negative lengthFrom start to end of string
UnicodePrefer $substrCP for character-safe cuts
Sample check$substr(["13Q1", 0, 2]) → "13"

Live Preview

Watch $substr cut a quarter code into year and quarter parts. Try the rest-of-string pattern with length -1.

Simulates $substr on ASCII text (same idea as the mongosh examples below).

Result
string = "13Q1"
start  = 0
length = 2

$substr → "13"

{ year: "13" }

Worked Walkthrough — 13Q1

A quarter code stores year digits then a quarter label. We pull "13" and "Q1" with two $substr calls.

Calculation
String: "13Q1"
Index:   0 1 2 3
Chars:   1 3 Q 1

Year:
  $substr(["$quarter", 0, 2]) → "13"

Quarter (rest):
  $substr(["$quarter", 2, -1]) → "Q1"

Check: "13" + "Q1" = "13Q1" ✓

MongoDB Examples

We store one inventory item with quarter code 13Q1. First we extract the year, then the rest of the string. Run these in mongosh after inserting the sample data once.

Example 1 — Sample Data

Imagine one product with item code ABC1 and quarter 13Q1. We save it in a collection named inventory.

mongosh
db.inventory.insertOne({
  _id: 1,
  item: "ABC1",
  quarter: "13Q1"
});

How the Data Is Stored in MongoDB

After the insert, MongoDB keeps one document in inventory. Run find() to see it:

mongosh
db.inventory.find()

Read that document like this:

Field in MongoDBValuePlain English
item"ABC1"Product code
quarter"13Q1"Year 13 + quarter Q1 in one string
Picture
quarter: 1 3 Q 1
index:   0 1 2 3

[0..2)  → "13"   year
[2..end] → "Q1"  quarter label

How It Works

  1. Insert once. insertOne adds a single inventory document.
  2. Quarter stays one string. Year and label are packed together until we slice them.
  3. find() shows the same shape. What you inserted is what you get back—ready for $substr next.

Example 2 — Extract the Year

Goal: take the first two characters of quarter as the year ("13").

mongosh
db.inventory.aggregate([
  {
    $addFields: {
      year: {
        $substr: ["$quarter", 0, 2]
      }
    }
  }
]);

How It Works

  1. Read the stored string. MongoDB already has quarter: "13Q1" from Example 1.
  2. Start at index 0. Extraction begins at the first character.
  3. Take length 2. That yields "13".
  4. Keep all fields. $addFields adds year next to the original quarter.

Example 3 — Extract the Rest (length -1)

Same document: start at index 2 and use length -1 to take everything remaining ("Q1").

mongosh
db.inventory.aggregate([
  {
    $addFields: {
      year: { $substr: ["$quarter", 0, 2] },
      qtr: { $substr: ["$quarter", 2, -1] }
    }
  }
]);

How It Works

  1. Same stored document. Still using "13Q1" from Example 1.
  2. Year again. Indices 0..2 → "13".
  3. Rest of string. Start at 2 with length -1 → "Q1".
  4. Easy check. Putting year and qtr back together rebuilds "13Q1".

Edge Cases & Pitfalls

Check these before using $substr in production pipelines.

deprecated

Prefer $substrBytes / $substrCP

$substr is a legacy alias. New code should call $substrBytes or $substrCP explicitly.

Unicode

Byte cuts can break characters

Because $substr aliases $substrBytes, slicing in the middle of a multi-byte character can error. Use $substrCP for character-safe cuts.

negative

Negative start vs negative length

Negative start → "". Negative length → take from start to the end of the string.

ASCII

Best for ASCII codes

Quarter codes, SKUs, and other ASCII prefixes are a natural fit. International text needs $substrCP.

Performance Notes

ApproachCostBest for
$substr alonePer-document string sliceFixed ASCII prefixes / suffixes
Two slices (year + rest)Still O(docs)Splitting packed codes
Store split fieldsNo runtime sliceHot filters on year / quarter

Substring extraction is cheap for short strings. If you filter on year often, store year as its own field. Filter early with $match when only some documents need slicing.

Key Takeaways

  • Role: extract a piece of a string by start + length.
  • Legacy: alias of $substrBytes (prefer the modern name).
  • Rest of string: use length -1.
  • Unicode: use $substrCP for character-safe cuts.

One line: $substr answers “what piece of this string do I get from this start for this length?”—as a legacy alias of $substrBytes.

Frequently Asked Questions

$substr returns part of a string starting at a zero-based index for a given length. For example, { $substr: [ "hello", 0, 2 ] } returns "he". Use it inside aggregation expression stages such as $project and $addFields.
Use { $substr: [ <string>, <start>, <length> ] }. Start is the zero-based index where extraction begins; length is how many units to include (or -1 for the rest of the string).
$substr is deprecated since MongoDB 3.4 and is an alias for $substrBytes (byte-based positions). Prefer $substrBytes or $substrCP (code-point positions) in new code. Prefer $substrCP for Unicode character slicing.
A negative start returns an empty string "". A negative length means “from start to the end of the string.”
As an alias of $substrBytes, null or a missing string field yields an empty string "". Prefer $ifNull when you want an explicit default.
Use $substrCP when you need character-safe slicing for accents and emoji. $substr / $substrBytes count bytes and can break multi-byte UTF-8 characters.

Next: $substrBytes

Use the modern byte-based substring operator that $substr aliases.

$substrBytes tutorial →

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.

9 people found this page helpful