MongoDB $indexOfCP Operator

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

What You’ll Learn

The $indexOfCP operator finds where a substring first appears inside a string, measured in Unicode code points (characters). It returns a zero-based index or -1 when the text is not found. Use it for international text, emoji, and any string work where character positions matter more than byte offsets.

01

Substring Search

Find text inside strings.

02

Code Point Index

Character-based positions.

03

Syntax

String, search, start, end.

04

$project Stage

Add computed index fields.

05

Use Cases

Unicode, emoji, i18n text.

06

Not Found

Returns -1 on miss.

Definition and Usage

In MongoDB’s aggregation framework, the $indexOfCP operator searches a string for the first occurrence of a substring and returns its zero-based code point index. For example, searching "Hello MongoDB" for "Mongo" returns 6. If the substring is absent, the result is -1.

Code points represent Unicode characters. Unlike $indexOfBytes, which counts UTF-8 bytes, $indexOfCP counts characters — so emoji and accented letters each count as one position. This makes it the better choice for human-readable text processing.

💡
Beginner Tip

For plain English (ASCII) text, $indexOfCP and $indexOfBytes usually return the same number. When your data includes emoji (🚀) or international characters (café, 中文), use $indexOfCP for predictable character positions and pair with $substrCP when slicing strings.

📝 Syntax

The $indexOfCP operator takes a string expression, a substring, and optional code point range bounds:

mongosh
{
  $indexOfCP: [
    <string expression>,
    <substring expression>,
    <start>,   // optional code point offset, default 0
    <end>      // optional code point offset, default string length in CP
  ]
}

Common Patterns

mongosh
// Basic substring search in a field
{ $indexOfCP: [ "$message", "hello" ] }

// Search from code point 3 onward
{ $indexOfCP: [ "$bio", "developer", 3 ] }

// Check if substring exists (index >= 0)
{ $gte: [
    { $indexOfCP: [ "$comment", "🚀" ] },
    0
] }

Syntax Rules

  • First argument — the string to search (field path like "$message" or a literal string).
  • Second argument — the substring to find (literal, field reference, or expression).
  • start — optional code point offset where the search begins (default 0).
  • end — optional code point offset before which the search stops (default string length in code points).
  • Returns -1 when the substring is not found in the specified range.
  • Indexes are measured in code points, not UTF-8 bytes.
  • Use inside stages like $project, $addFields, $set, and $cond.

💡 $indexOfCP vs $indexOfBytes

Choose the right string index operator for your data:

ASCII / English only → both operators usually return the same index
Emoji / international text → prefer $indexOfCP for character positions
Slicing after the index → pair $indexOfCP with $substrCP, not $substrBytes

⚡ Quick Reference

QuestionAnswer
Operator typeAggregation expression operator (string)
Syntax{ $indexOfCP: [ string, substring, start?, end? ] }
FoundZero-based code point index (0, 1, 2, …)
Not found-1
Common stages$project, $addFields, $cond
Basic
{
  $indexOfCP: [
    "$message",
    "hello"
  ]
}

Code point index

Not found
{
  $indexOfCP: [
    "hello",
    "xyz"
  ]
}

Returns -1

With start
{
  $indexOfCP: [
    "$bio",
    "dev",
    5
  ]
}

Search from CP 5

Exists check
{
  $gte: [
    { $indexOfCP: [
      "$text", "🚀"
    ]},
    0
  ]
}

true if emoji found

Examples Gallery

Walk through sample message data, find substring positions with $project, and see why code point indexing matters for Unicode text.

📚 Find a Substring Position

Start with a messages collection and locate where a keyword appears in each document’s body field.

Sample Input Documents

Suppose you have a messages collection with body and locale fields:

mongosh
[
  { "_id": ObjectId("609c26812e9274a86871bc6a"), "body": "Welcome to MongoDB tutorials!", "locale": "en" },
  { "_id": ObjectId("609c26812e9274a86871bc6b"), "body": "Launch day 🚀 Let's go!", "locale": "en" },
  { "_id": ObjectId("609c26812e9274a86871bc6c"), "body": "Bienvenue sur CodeToFun", "locale": "fr" }
]

Example 1 — Basic $indexOfCP on a Field

Find the code point index of "MongoDB" in each message body:

mongosh
db.messages.aggregate([
  {
    $project: {
      body: 1,
      mongoIndex: {
        $indexOfCP: [ "$body", "MongoDB" ]
      }
    }
  }
])

How It Works

  • In "Welcome to MongoDB tutorials!", "MongoDB" starts at code point index 11.
  • When the substring is missing, MongoDB returns -1 instead of throwing an error.
  • For ASCII text like this example, the result matches what $indexOfBytes would return.

📈 Practical Patterns

Combine $indexOfCP with Unicode text, existence checks, and conditional logic.

Example 2 — Search in Text with Emoji

Find the rocket emoji in a message — code point indexing treats emoji as single characters:

mongosh
db.messages.aggregate([
  {
    $project: {
      body: 1,
      rocketIndex: {
        $indexOfCP: [ "$body", "🚀" ]
      },
      rocketIndexBytes: {
        $indexOfBytes: [ "$body", "🚀" ]
      }
    }
  }
])

How It Works

The rocket emoji 🚀 is one Unicode code point but uses multiple UTF-8 bytes. $indexOfCP reports the character position users expect. $indexOfBytes reports the byte offset — useful for binary work, but less intuitive for display logic. For emoji-heavy content, prefer $indexOfCP.

Example 3 — Check Whether a Substring Exists

Convert the code point index into a boolean hasRocket field:

mongosh
db.messages.aggregate([
  {
    $project: {
      body: 1,
      hasRocket: {
        $gte: [
          { $indexOfCP: [ "$body", "🚀" ] },
          0
        ]
      }
    }
  }
])

How It Works

When the index is -1, $gte returns false. When the substring is found (index 0 or higher), the result is true. This pattern works for any keyword or symbol, including multi-byte Unicode characters.

Example 4 — $indexOfCP Inside $cond

Label messages as promotional or standard based on whether they contain a launch keyword:

mongosh
db.messages.aggregate([
  {
    $project: {
      body: 1,
      messageType: {
        $cond: [
          {
            $gte: [
              { $indexOfCP: [ "$body", "Launch" ] },
              0
            ]
          },
          "promotional",
          "standard"
        ]
      }
    }
  }
])

How It Works

If $indexOfCP finds "Launch", the index is >= 0 and $cond outputs "promotional". Otherwise the message is labeled "standard". Pair with $substrCP to extract text starting at the found position.

Bonus — Combine with $substrCP

After finding an index, extract the text that follows a keyword:

mongosh
db.messages.aggregate([
  {
    $addFields: {
      keywordIndex: {
        $indexOfCP: [ "$body", "MongoDB" ]
      }
    }
  },
  {
    $project: {
      body: 1,
      afterKeyword: {
        $cond: [
          { $gte: [ "$keywordIndex", 0 ] },
          {
            $substrCP: [
              "$body",
              { $add: [ "$keywordIndex", 7 ] },
              20
            ]
          },
          null
        ]
      }
    }
  }
])

How It Works

First find the code point index of "MongoDB" (7 characters long), then use $substrCP with index + 7 to read the next 20 code points. Using $substrCP (not $substrBytes) keeps slicing correct for Unicode text.

🚀 Use Cases

  • International text — search substrings in multilingual content with correct character positions.
  • Emoji and symbols — detect or locate emoji in social posts, comments, and chat messages.
  • Keyword detection — flag promotional, spam, or policy-related phrases in message bodies.
  • String slicing — pair with $substrCP to extract text after a found keyword.

🧠 How $indexOfCP Works

1

MongoDB reads the string and substring

The pipeline evaluates the source string (e.g. "$body") and the text to find (e.g. "MongoDB" or an emoji).

Input
2

$indexOfCP scans the code point range

MongoDB walks from start to end code point offsets, comparing substrings until a match is found.

Search
3

The code point index is stored

A zero-based character index is written to your output field, or -1 if no match exists in the range.

Output
=

Unicode-safe positions

You get character-based index data ready for existence checks, labeling, and $substrCP extraction.

Conclusion

The $indexOfCP operator is the Unicode-friendly way to find substrings in MongoDB aggregation pipelines. It measures positions in code points rather than bytes, which makes it the right choice for emoji, accented characters, and international text.

For beginners, the key idea is simple: wrap your string and substring in { $indexOfCP: [ ... ] } inside a stage like $project. A result of -1 means “not found”; any index 0 or higher means the substring was located. For ASCII-only byte work, $indexOfBytes is also available.

💡 Best Practices

✅ Do

  • Use $indexOfCP for emoji and international text
  • Pair with $substrCP when slicing after a found index
  • Check for -1 before using the index in $substrCP
  • Use $gte: [ { $indexOfCP: ... }, 0 ] for existence booleans
  • Prefer code points when positions must match what users see

❌ Don’t

  • Use $indexOfCP as a query filter outside expressions
  • Mix $indexOfCP indexes with $substrBytes (use $substrCP)
  • Confuse it with $indexOfArray (arrays vs strings)
  • Assume byte and code point indexes always match
  • Forget that missing substrings return -1, not null

Key Takeaways

Knowledge Unlocked

Five things to remember about $indexOfCP

Use these points when searching substrings in Unicode text.

5
Core concepts
📝 02

Four Arguments

string, search, start, end.

Syntax
🛠 03

Pipeline Stages

$project, $addFields, $cond.

Usage
🚀 04

Emoji Safe

One emoji = one code point.

Use case
05

Not Found

Returns -1.

Edge case

❓ Frequently Asked Questions

$indexOfCP returns the zero-based code point index of the first occurrence of a substring inside a string. It is an aggregation expression operator used inside stages like $project and $addFields.
The syntax is { $indexOfCP: [ <string>, <substring>, <start>, <end> ] }. The start and end arguments are optional code point offsets that limit the search range.
It returns -1 when the substring is not present in the string (within the optional start/end code point range).
$indexOfCP counts Unicode code points (characters). $indexOfBytes counts UTF-8 byte positions. For plain ASCII text they usually match; for emoji or multi-byte characters the indexes can differ.
Use $indexOfCP when you work with international text, emoji, or accented characters and need character-based positions. Use $indexOfBytes when byte-level offsets matter or when pairing with $substrBytes.

Continue the Operator Series

Move on to $isArray to test array types, or review $indexOfBytes for byte-level string indexing.

Next: $isArray →

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