Evaluation Operators
Learn how to query documents using $regex for pattern matching, $expr for comparing fields, and $text for full-text search.
Evaluation Operators
Evaluation operators go beyond simple value comparisons. They let you match documents based on patterns, compare fields against each other, and run full-text searches.
$regex— match a field against a regular expression pattern$expr— compare fields within the same document using expressions$text— run a full-text search across indexed string fields
$regex
$regex matches documents where a string field matches a regular expression pattern. Use it when you need to search by partial text, pattern, or case-insensitive match.
Syntax
db.collection.find({ field: { $regex: /pattern/ } })
// or
db.collection.find({ field: { $regex: "pattern", $options: "i" } })Example — Find students whose name starts with "Ali"
db.students.find({ name: { $regex: /^Ali/ } })The ^ means "starts with". This returns Ali Hassan, Ali Ahmed, and so on.
Example — Find students whose name ends with "Khan"
db.students.find({ name: { $regex: /Khan$/ } })The $ means "ends with".
Example — Find students whose name contains "ahmed" — case insensitive
db.students.find({
name: { $regex: /ahmed/i }
})The i flag makes the match case-insensitive. This returns Ahmed, ahmed, AHMED — all variations.
Using $options
You can also write the pattern as a string and pass options separately:
db.students.find({
name: { $regex: "ahmed", $options: "i" }
})Common $options flags:
| Flag | Meaning |
|---|---|
i | Case-insensitive match |
m | Multiline — ^ and $ match start and end of each line |
s | Allows . to match newline characters |
x | Ignore whitespace in the pattern |
Example — Find courses whose title contains "science"
db.courses.find({
title: { $regex: /science/i }
})This returns "Computer Science", "Social Science", "Science" — anything containing the word.
Example — Find teachers whose email is from a specific domain
db.teachers.find({
email: { $regex: /@school\.com$/ }
})$regex queries on large collections without an index are slow — MongoDB has to scan every document and test the pattern. For heavy text search needs, use a text index with $text instead. Use $regex for simple pattern matching on small collections or indexed fields.
$expr
$expr lets you compare two fields within the same document using aggregation expressions. Regular query operators compare a field against a fixed value — $expr compares a field against another field.
Syntax
db.collection.find({
$expr: { $operator: ["$field1", "$field2"] }
})Notice the $ prefix on field names inside $expr — this tells MongoDB to treat them as field references, not literal strings.
Example — Find courses where totalStudents exceeds capacity
Imagine courses have both a totalStudents field and a capacity field:
db.courses.find({
$expr: { $gt: ["$totalStudents", "$capacity"] }
})This finds courses where totalStudents is greater than capacity — comparing two fields in the same document. You cannot do this with regular $gt because $gt compares a field against a fixed value, not another field.
Example — Find students where their exam score is greater than their assignment score
db.students.find({
$expr: { $gt: ["$examScore", "$assignmentScore"] }
})Example — Find students whose age matches their expected grade year
// Students where age minus 5 equals their school year number
db.students.find({
$expr: {
$eq: [
{ $subtract: ["$age", 5] },
"$schoolYear"
]
}
})$expr supports all aggregation expressions — $add, $subtract, $multiply, $divide, and more. We cover these in depth in the Aggregation section.
Example — Find students where first semester score is higher than second semester
db.students.find({
$expr: { $gt: ["$semester1Score", "$semester2Score"] }
})$expr is a bridge between the query layer and the aggregation layer. If you find yourself needing to compare fields or do calculations inside a query filter, $expr is the tool for the job.
$text
$text performs a full-text search on fields that have a text index. It is designed for searching natural language content — like searching for a word or phrase across a name or description field.
Step 1 — Create a text index
Before you can use $text, you must create a text index on the field you want to search:
// Create a text index on the name field
db.students.createIndex({ name: "text" })
// Create a text index on multiple fields
db.courses.createIndex({ title: "text", description: "text" })We cover indexes in depth in the Indexes section. For now, just know that $text requires one.
Step 2 — Search with $text
// Find students whose name contains "Hassan"
db.students.find({
$text: { $search: "Hassan" }
})Syntax
db.collection.find({
$text: {
$search: "search terms",
$caseSensitive: false, // optional — default is false
$diacriticSensitive: false // optional — default is false
}
})Searching multiple words
When you pass multiple words, $text returns documents that contain any of those words (OR behavior):
// Find courses that mention "Math" OR "Science"
db.courses.find({
$text: { $search: "Math Science" }
})Searching an exact phrase
Wrap the phrase in escaped quotes to search for an exact phrase:
// Find courses with the exact phrase "Computer Science"
db.courses.find({
$text: { $search: "\"Computer Science\"" }
})Excluding a word
Prefix a word with - to exclude documents that contain it:
// Find courses that mention "Science" but NOT "Computer"
db.courses.find({
$text: { $search: "Science -Computer" }
})Sorting by relevance score
$text search assigns each result a relevance score. You can sort by it to show the most relevant results first:
db.courses.find(
{ $text: { $search: "Math Science" } },
{ score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })$text is much faster than $regex for searching text content because it uses an index. For any feature where users search by keyword — like a search bar — always use $text with a text index instead of $regex.
$regex vs $text — When to Use Which
$regex | $text | |
|---|---|---|
| Requires index | No | Yes — text index required |
| Speed on large collections | Slow | Fast |
| Pattern matching | ✅ Yes | ❌ No |
| Partial word match | ✅ Yes | ❌ No — whole words only |
| Multi-field search | ❌ One field at a time | ✅ Yes — across all text-indexed fields |
| Relevance scoring | ❌ No | ✅ Yes |
| Best for | Patterns, formats, small data | Keyword search, search bars |
School System Examples
// Find students whose name starts with "Ali"
db.students.find({ name: { $regex: /^Ali/i } })
// Find students whose name contains "ahmed" — any case
db.students.find({ name: { $regex: /ahmed/i } })
// Find teachers with a school.com email
db.teachers.find({ email: { $regex: /@school\.com$/i } })
// Find courses whose title contains "science" — any case
db.courses.find({ title: { $regex: /science/i } })
// Find courses where totalStudents exceeds capacity
db.courses.find({
$expr: { $gt: ["$totalStudents", "$capacity"] }
})
// Find students where exam score is higher than assignment score
db.students.find({
$expr: { $gt: ["$examScore", "$assignmentScore"] }
})
// Full text search — create index first
db.courses.createIndex({ title: "text", description: "text" })
// Search for courses mentioning "computer"
db.courses.find({ $text: { $search: "computer" } })
// Search for exact phrase
db.courses.find({ $text: { $search: "\"computer science\"" } })
// Search and sort by relevance
db.courses.find(
{ $text: { $search: "math science" } },
{ score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })Quick Reference
| Operator | What it does | Example |
|---|---|---|
$regex | Match a pattern in a string field | { name: { $regex: /^Ali/i } } |
$expr | Compare two fields in the same document | { $expr: { $gt: ["$score1", "$score2"] } } |
$text | Full-text search on text-indexed fields | { $text: { $search: "math" } } |
For a student-facing search feature in your school app — like searching for a course by name — create a text index and use $text. It is faster, smarter, and supports relevance scoring. Save $regex for internal tools and admin queries where you need pattern matching.