MongoDB $where Operator

Beginner
⏱️ 9 min read
📚 Updated: Jul 2026
🎯 5 Examples
Query / JavaScript

What You’ll Learn

The $where operator runs a JavaScript expression against each document in a find() query. It is a legacy query operator — useful to understand for reading old code, but modern MongoDB apps should prefer $expr and native operators instead.

01

JS Filter

Custom logic.

02

this Keyword

Current document.

03

String or Fn

Two syntax forms.

04

find() Only

Query operator.

05

Deprecated

Use $expr instead.

06

Security

Avoid user input.

Definition and Usage

In MongoDB, the $where operator is a query operator that evaluates a JavaScript expression for every document in a collection. If the expression returns true, the document is included in the result set. Inside the script, this refers to the current document, so you can write conditions like this.qty * this.price > 1000.

MongoDB deprecated $where in version 4.4 because it forces a collection scan, cannot use indexes effectively, and introduces security risks when user input is embedded in JavaScript strings. For new projects, use $expr with aggregation operators such as $multiply, $gt, and $eq.

💡
Beginner Tip

Learn $where to read legacy tutorials and old codebases, but write new queries with $expr. Native operators are faster, safer, and easier to maintain.

📝 Syntax

$where accepts either a JavaScript string or a function:

String Form

mongosh
{
  $where: "<JavaScript expression as string>"
}

// Example:
db.products.find({
  $where: "this.qty * this.price > 1000"
})

Function Form

mongosh
{
  $where: function() {
    return <boolean expression>;
  }
}

// Example:
db.products.find({
  $where: function() {
    return this.qty * this.price > 1000;
  }
})

Modern Alternative with $expr

mongosh
// Preferred in modern MongoDB:
db.products.find({
  $expr: {
    $gt: [
      { $multiply: ["$qty", "$price"] },
      1000
    ]
  }
})

Syntax Rules

  • Query only — use in find() filters, not as an aggregation expression operator.
  • this — refers to the document being evaluated (this.price, this.tags).
  • Return value — must be truthy to include the document.
  • Performance — evaluates JavaScript on every document; avoid on large collections.
  • Security — never concatenate untrusted user input into the JavaScript string.
  • Status — deprecated since MongoDB 4.4; may be removed in future releases.

⚠ Deprecated — Prefer $expr

Performance — $where scans every document and runs JavaScript; indexes cannot help much
Security — embedding user input in JS strings can enable injection attacks
Modern fix — use $expr with $multiply, $gt, $eq, $size, etc.
For custom JS in pipelines (not queries), see the $function operator

⚡ Quick Reference

QuestionAnswer
Operator typeQuery operator (JavaScript filter)
Syntax{ $where: "..." } or { $where: function() { ... } }
Document referencethis.fieldName
Common usagefind() only
Modern alternative$expr with aggregation operators
StatusDeprecated (MongoDB 4.4+)
String
{
  $where: "this.score > 90"
}

JS string form

Function
{
  $where: function() {
    return this.score > 90;
  }
}

Function form

$expr alt
{
  $expr: {
    $gt: ["$score", 90]
  }
}

Modern replacement

Compare fields
{
  $where: "this.end > this.start"
}

Field vs field

Examples Gallery

Filter a products collection with $where, then see the recommended $expr equivalents for the same logic.

📚 Custom JavaScript Filters

Find products where quantity times price exceeds a threshold using $where.

Sample Input Documents

Suppose you have a products collection:

mongosh
[
  { "_id": 1, "name": "Widget A", "qty": 50,  "price": 25.00 },
  { "_id": 2, "name": "Widget B", "qty": 10,  "price": 120.00 },
  { "_id": 3, "name": "Widget C", "qty": 100, "price": 8.50 },
  { "_id": 4, "name": "Widget D", "qty": 5,   "price": 250.00 }
]

Example 1 — $where with a JavaScript String

Find products where qty * price is greater than 1000:

mongosh
db.products.find({
  $where: "this.qty * this.price > 1000"
})

// Matches:
// Widget A → 50 * 25   = 1250  ✓
// Widget B → 10 * 120  = 1200  ✓
// Widget D → 5 * 250   = 1250  ✓

How It Works

MongoDB evaluates the JavaScript string on each document. this.qty and this.price read field values from the current document.

📈 More Patterns & Modern Replacements

Function syntax, field comparisons, array checks, and $expr alternatives.

Example 2 — $where with a Function

The function form is equivalent but easier to read for multi-line logic:

mongosh
db.products.find({
  $where: function() {
    return this.qty * this.price > 1000;
  }
})

How It Works

The function must return a boolean. Use this form when the condition needs intermediate variables or multiple statements.

Example 3 — Compare Two Fields in the Same Document

Find events where the end date is after the start date (validation check):

mongosh
db.events.find({
  $where: "this.endDate > this.startDate"
})

// $expr alternative (preferred):
db.events.find({
  $expr: {
    $gt: ["$endDate", "$startDate"]
  }
})

How It Works

$where can compare fields within the same document. The $expr version does the same without running JavaScript on every row.

Example 4 — Check Array Length with $where

Find products with more than two tags:

mongosh
db.products.find({
  $where: "this.tags && this.tags.length > 2"
})

// $expr alternative (preferred):
db.products.find({
  $expr: {
    $gt: [{ $size: "$tags" }, 2]
  }
})

How It Works

JavaScript can inspect array properties directly. In modern MongoDB, $size inside $expr is the safer replacement.

Example 5 — Rewrite $where as $expr (Recommended)

Replace the product total-value filter with native operators:

mongosh
// Legacy $where:
db.products.find({
  $where: "this.qty * this.price > 1000"
})

// Modern $expr (same result, better performance):
db.products.find({
  $expr: {
    $gt: [
      { $multiply: ["$qty", "$price"] },
      1000
    ]
  }
})

// Also works in aggregation $match:
db.products.aggregate([
  {
    $match: {
      $expr: {
        $gt: [
          { $multiply: ["$qty", "$price"] },
          1000
        ]
      }
    }
  }
])

How It Works

$expr lets you use aggregation expression operators in query filters. This is the pattern MongoDB recommends instead of $where.

Bonus — Security: Never Build $where from User Input

This pattern is dangerous and should never be used in production:

mongosh
// DANGEROUS — do not do this:
var userInput = "1000; return true";  // malicious input
db.products.find({
  $where: "this.qty * this.price > " + userInput
})

// SAFE — use parameterized $expr instead:
var threshold = 1000;
db.products.find({
  $expr: {
    $gt: [
      { $multiply: ["$qty", "$price"] },
      threshold
    ]
  }
})

How It Works

Concatenating user input into a JavaScript string can allow code injection. Native operators with bound values avoid executing arbitrary scripts.

🚀 Use Cases

  • Legacy codebases — understand and migrate old queries that still use $where.
  • Field comparisons — filter when one field must be greater than another (prefer $expr today).
  • Complex conditions — prototype logic quickly in tutorials (rewrite with native operators for production).
  • One-off admin scripts — ad hoc filtering on small collections during data exploration.

🧠 How $where Works

1

MongoDB scans documents

Each document in the collection is considered as a candidate match.

Scan
2

JavaScript runs on each doc

The $where string or function executes with this bound to the current document.

Evaluate
3

Truthy results are kept

Documents where the expression returns true pass the filter and appear in query results.

Filter
=

Custom-filtered set

For production, achieve the same outcome with $expr and native operators.

Conclusion

The $where operator lets you filter documents with JavaScript in find() queries. It is useful for understanding legacy MongoDB code, but it is deprecated because of performance and security concerns.

For new development, use $expr with aggregation operators. For custom JavaScript inside pipelines (not ad hoc query filters), see $function. Next in the series: $year.

💡 Best Practices

✅ Do

  • Rewrite $where queries as $expr when migrating legacy code
  • Use native operators like $multiply, $gt, and $size
  • Limit $where to small collections in one-off scripts only
  • Document why a legacy query used JavaScript if you cannot migrate yet
  • Use $function for controlled JS inside aggregation pipelines

❌ Don’t

  • Use $where in new production application code
  • Concatenate user input into $where JavaScript strings
  • Run $where on large collections expecting fast performance
  • Assume indexes will speed up $where filters
  • Confuse query $where with pipeline $function

Key Takeaways

Knowledge Unlocked

Five things to remember about $where

Use these points when reading or migrating legacy MongoDB queries.

5
Core concepts
🛠 02

this.field

Current document.

Syntax
03

Deprecated

Since MongoDB 4.4.

Status
🔄 04

Use $expr

Modern replacement.

Migrate
🔒 05

No User Input

Injection risk.

Security

❓ Frequently Asked Questions

$where runs a JavaScript expression against each document in a find() query. The expression must return true to include the document. Inside the script, this refers to the current document.
You can pass a string: { $where: "this.qty * this.price > 1000" } or a function: { $where: function() { return this.qty * this.price > 1000; } }. Use find() or $match in rare legacy cases.
No. MongoDB deprecated $where in version 4.4 because it is slow, cannot use indexes efficiently, and poses security risks. Prefer $expr with aggregation operators like $multiply, $gt, and $eq instead.
this refers to the current document being evaluated. You can read fields with this.fieldName, such as this.price or this.tags.length.
Use $expr in find() or aggregation $match: { $expr: { $gt: [ { $multiply: ["$qty", "$price"] }, 1000 ] } }. Native operators are faster, index-friendly where possible, and avoid arbitrary JavaScript.

Continue the Operator Series

Move on to $year for extracting the calendar year from dates, or review $function for pipeline JavaScript.

Next: $year →

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