Regular expressions provide a powerful method for matching text patterns within MongoDB documents. The $regex operator enables this functionality, utilizing the PCRE (Perl Compatible Regular Expressions) library.
Consider a blog_posts collection with the following document structure:
{
"content": "Explore the MongoDB tutorials on this site",
"categories": [
"mongodb",
"tutorial"
]
}
Basic Pattern Matching
To locate documents where the content field contains the substring "tutorial", you can use either of these equivalent queries:
db.blog_posts.find({ content: { $regex: "tutorial" } })
// Alternative syntax
db.blog_posts.find({ content: /tutorial/ })
Case-Insensitive Matching
For case-insensitive searches, include the $options parameter with the value "i".
db.blog_posts.find({ content: { $regex: "tutorial", $options: "i" } })
This query would match documents containing "tutorial", "Tutorial", or "TUTORIAL".
Matching Within Array Fields
Regular expressions can also be applied to elements within array fields, which is useful for searching tags or categories.
db.blog_posts.find({ categories: { $regex: "^tut" } })
This finds documents where any element in the categories array starts with "tut" (e.g., "tutorial").
Query Performance and Indexes
Using indexes on fields involved in regex queries can significantly improve performance. Queries are most efficient when the regex pattern is anchored at the beginning (a prefix expression).
// Efficient: Uses an index if one exists on 'content'
db.blog_posts.find({ content: { $regex: "^Explore" } })
// Less efficient: Cannot typically use an index effectively
db.blog_posts.find({ content: { $regex: "torial$" } })
When constructing regex patterns dynamically using variables, ensure proper evaluation to avoid silent failures.
let searchTerm = "tutorial";
let dynamicPattern = eval("/" + searchTerm + "/i");
// This is equivalent to: { $regex: "tutorial", $options: "i" }
db.blog_posts.find({ content: dynamicPattern });
Regex Oeprator Syntax and Options
The $regex operator can be used in several forms:
{ field: { $regex: /pattern/, $options: '<options>' } }
{ field: { $regex: 'pattern', $options: '<options>' } }
{ field: /pattern/<options> } // Regex literal syntax
Key $options flags:
i: Case-insensitive matchnig.m: Multi-line mode. Changes the behavior of^and$to match the start/end of each line.s: Single-line (dot-all) mode. Causes the dot (.) to match newline characters (\n).x: Ignores unescaped whitespace and allows comments in the pattern.
These options can be combined, e.g., "si".
Important Usage Distinctions
- Within an
$inoperator, you must use the regex literal syntax.db.users.find({ name: { $in: [ /^joe/i, /^jack/ ] } }) - When combining conditions with an implicit
$and(e.g., also using$nin), you must use the explicit$regexoperator.// Correct db.users.find({ name: { $regex: /^jo/i, $nin: ['john'] } }) - The
xandsoptions can only be specified within the$optionsstring of the$regexoperator, not in a regex literal.// Valid db.data.find({ text: { $regex: /m.*line/, $options: "si" } })