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.
Fundamentals
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.
Foundation
📝 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
// "Launch day 🚀 Let's go!"
// → rocketIndex: 11 (code point position)
// → rocketIndexBytes: 11 (byte position — may differ for other emoji)
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:
// body contains 🚀 → hasRocket: true
// body without 🚀 → hasRocket: false
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:
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:
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.
Applications
🚀 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.
Wrap Up
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.
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
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about $indexOfCP
Use these points when searching substrings in Unicode text.
5
Core concepts
🌐01
Code Point Index
Character-based positions.
Purpose
📝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.