mongodb 7.5.0Find MongoDB Documents That Contain a String
Query MongoDB string fields with exact values, regular expressions, case-insensitive matching, escaping, indexes, and safer alternatives for text search.
What “contains” means in MongoDB
MongoDB does not have one universal contains operator for strings. The correct query depends on the intended semantics:
- equality when the entire stored value must match;
- a regular expression when a substring or pattern must match;
- a text index when the application needs word-oriented text search;
- MongoDB Search when an Atlas deployment needs richer search behavior.
Start with the narrowest operation that expresses the requirement. A regular expression can be convenient for an investigation, but an unanchored expression may examine many documents and should not automatically become a production search design.
Create an isolated collection for the examples:
const products = db.collection("string_search_products");
products.deleteMany({ tutorial: "contains-string" });
products.insertMany([
{ name: "Mechanical Keyboard", sku: "KEY-75-BLK", tags: ["keyboard", "usb-c"], tutorial: "contains-string" },
{ name: "Compact keyboard case", sku: "CASE-75-GRN", tags: ["accessory"], tutorial: "contains-string" },
{ name: "Wireless Mouse", sku: "MOUSE-WL", tags: ["mouse", "wireless"], tutorial: "contains-string" },
{ name: "Keyboard Cleaning Brush", sku: "BRUSH-01", tags: ["maintenance"], tutorial: "contains-string" }
]);
Every query below includes the tutorial marker so the examples remain scoped to their own data.
Match the whole string exactly
Use equality when the field must contain one exact value:
products.find({
tutorial: "contains-string",
sku: "KEY-75-BLK"
});
Equality communicates a stronger requirement than a regular expression and is straightforward to support with an index. It is also case-sensitive for ordinary string comparisons unless the query or index uses a collation.
For an array of strings, equality matches when the array contains the exact element:
products.find({
tutorial: "contains-string",
tags: "keyboard"
});
This does not mean that any tag containing those characters will match. It means one array element equals "keyboard".
Find a substring with a regular expression
Use a regular expression for a direct substring match:
products.find({
tutorial: "contains-string",
name: /keyboard/
});
The query matches Compact keyboard case but not Mechanical Keyboard because regular expressions are case-sensitive by default. Add the i option only when case-insensitive behavior is part of the requirement:
products.find({
tutorial: "contains-string",
name: /keyboard/i
});
This returns the three names containing either keyboard or Keyboard. It does not tokenize the field or understand language; it only applies a regular-expression pattern.
The equivalent BSON query can use $regex and $options:
products.find({
tutorial: "contains-string",
name: { $regex: "keyboard", $options: "i" }
});
The literal form is concise for a fixed developer-authored pattern. The $regex form is useful when a reviewed application value supplies the pattern and options.
Escape user-provided text
Regular-expression characters such as ., *, +, ?, (, ), [, ], {, }, ^, $, |, and \\ change pattern meaning. Never place untrusted text directly into new RegExp() and assume it will be interpreted literally.
Escape the characters first:
function escapeRegex(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
const searchText = "KEY-75";
const literalPattern = new RegExp(escapeRegex(searchText), "i");
products.find({
tutorial: "contains-string",
sku: literalPattern
});
Also bound the accepted length. Escaping prevents syntax from changing meaning, but very long or adversarial patterns can still create expensive work. An API should validate the input before it reaches the database.
Use anchors when the position is known
Anchors make the intended position explicit:
// Starts with CASE-
products.find({ tutorial: "contains-string", sku: /^CASE-/ });
// Ends with -BLK
products.find({ tutorial: "contains-string", sku: /-BLK$/ });
A case-sensitive prefix expression can often make better use of an index than an unanchored contains expression. Confirm the actual access path with explain("executionStats") instead of assuming that an index name proves efficient execution:
products.createIndex({ sku: 1 }, { name: "sku_lookup" });
products.find({
tutorial: "contains-string",
sku: /^KEY-/
}).explain("executionStats");
Review totalDocsExamined, totalKeysExamined, the winning plan, and the number of returned documents. Test with representative data; a four-document tutorial collection cannot predict production performance.
Decide when regex is the wrong tool
Use a text index for word-oriented search across selected fields, or MongoDB Search on Atlas when the requirement includes analyzers, relevance, autocomplete, fuzzy matching, or other search features. These approaches have different syntax, deployment requirements, and ranking behavior from $regex.
Do not apply $regex to every field in every collection for a general search box. That pattern is difficult to index, expensive to bound, and unclear about which data should be searchable. MongoG's Global Search is also intentionally bounded and intended for investigation, not as an application search engine.
Verify the result in MongoG
Run the examples in a MongoG query tab, inspect the returned documents, and use selected-statement execution to compare case-sensitive and case-insensitive forms. Then add a name containing a literal period or plus sign and confirm that the escaping helper treats it as text.
Remove the tutorial records when finished:
products.deleteMany({ tutorial: "contains-string" });
Continue with broader MongoDB query examples, learn array query patterns, or use indexes and explain plans to evaluate an important search path.