MongoDB $where Operator

Beginner
5 min read
Updated: Oct 2026
3 examples
Live preview

What Is $where?

$where is a MongoDB query operator that runs a JavaScript expression on each document in find(). Keep the document when the expression returns true. Inside the script, this is the current document. For new work, prefer $expr.

Remember
$where = JavaScript filter for find()

{ $where: "this.qty * this.price > 1000" }
{ $where: function() { return this.qty * this.price > 1000; } }

this → current document
return true → keep document

Prefer today:
{ $expr: { $gt: [ { $multiply: ["$qty","$price"] }, 1000 ] } }

Slow · hard to index · never build from user input
UsePrefer
Legacy JS filter in find()$where (learn / maintain only)
Field math / compare fields$expr
Simple field checksNormal query ops ($gt, $eq)

How to Use $where in MongoDB

Write a boolean JavaScript check, pass it to $where, then prefer rewriting it with $expr.

  1. Start from a find() filter (not an aggregation expression stage).
  2. Write a string or function that reads this.field and returns true/false.
  3. Test on a small collection so you can see which rows match.
  4. Rewrite the same logic with $expr + native operators for production.
PieceRequired?Role
$whereYesRun JS per document in find()
String or functionYesMust evaluate to a boolean
thisYes (in script)Current document being tested

Pseudocode

Pseudocode
for each document in collection:
    this = document
    ok = evaluate(javascriptExpression)   // must be boolean
    if ok is true:
        keep document
    else:
        skip document

Cheat Sheet

Keep these facts handy while reading or replacing $where filters.

TopicDetail
TypeQuery operator for find()
String form{ $where: "this.a > this.b" }
Function form{ $where: function() { return this.a > this.b; } }
thisCurrent document
Modern alt$expr + $gt / $multiply / …
IndexesUsually cannot use indexes well
SecurityNever concatenate user input into $where

Live Preview

Simulate $where: "this.qty * this.price > threshold" on the sample products. Change the threshold and run.

Simulates the same product filter used in the mongosh examples below.

Result
$where: "this.qty * this.price > 1000"

Widget A: 50 * 25 = 1250 → keep
Widget B: 10 * 120 = 1200 → keep
Widget C: 100 * 8.5 = 850 → skip
Widget D: 5 * 250 = 1250 → keep

matched: 3

Worked Walkthrough — Inventory Value

One product has qty: 50 and price: 25. Goal: keep it only if inventory value is greater than 1000.

Calculation
Document:
  { name: "Widget A", qty: 50, price: 25 }

$where: "this.qty * this.price > 1000"

this.qty * this.price
  = 50 * 25
  = 1250

1250 > 1000 → true → keep document

Same idea with $expr (preferred):
  $multiply(["$qty","$price"]) → 1250
  $gt([1250, 1000]) → true

MongoDB Examples

We use a small products collection. First filter with $where, then rewrite the same rule with $expr. Run these in mongosh after inserting the sample data once.

Example 1 — Sample Data

Imagine four products with quantity and unit price. We will filter by inventory value: qty * price.

mongosh
db.products.insertMany([
  { _id: 1, name: "Widget A", qty: 50, price: 25 },
  { _id: 2, name: "Widget B", qty: 10, price: 120 },
  { _id: 3, name: "Widget C", qty: 100, price: 8.5 },
  { _id: 4, name: "Widget D", qty: 5, price: 250 }
]);

How the Data Is Stored in MongoDB

After the insert, MongoDB keeps four documents in products. Run find() to see them:

mongosh
db.products.find()

Read each document like this:

Field in MongoDBExamplePlain English
_id1Document id (row number for this lesson)
name"Widget A"Product name
qty50Units in stock
price25Unit price

How It Works

  1. Insert once. insertMany adds four product documents to products.
  2. Fields stay numeric. qty and price are numbers so multiplication works in JS or in $multiply.
  3. find() shows the same shape. Ready for $where and $expr next.

Example 2 — Filter with $where

Goal: keep products whose inventory value (qty * price is greater than 1000.

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

How It Works

  1. Visit each document. MongoDB runs the JavaScript string once per product.
  2. Read with this. this.qty and this.price come from the current row.
  3. Keep when true. Widget A = 1250, B = 1200, D = 1250 (keep); Widget C = 850 (skip).

Example 3 — Prefer $expr

Same rule, rewritten with native aggregation operators. This is the pattern to use in new code.

mongosh
db.products.find({
  $expr: {
    $gt: [
      { $multiply: ["$qty", "$price"] },
      1000
    ]
  }
});

How It Works

  1. Same stored documents. Still using the four products from Example 1.
  2. Multiply with operators. $multiply computes qty * price.
  3. Compare with $gt. $expr lets that math run inside find().
  4. Same matches. A, B, and D still pass; C still fails—without running custom JavaScript.

Edge Cases & Pitfalls

Check these before using $where in any real application.

security

Never build $where from user input

String concatenation into $where is an injection risk. Pass numbers/strings into $expr parameters instead.

speed

It is usually slow

JavaScript runs per document and typically cannot use indexes. Prefer normal query operators or $expr.

boolean

Expression must return boolean

Non-boolean results lead to surprising keep/skip behavior. Always return an explicit true or false.

server

Server-side JS must be allowed

Some deployments disable server-side JavaScript. In those environments $where fails; $expr still works.

Performance Notes

ApproachCostBest for
$whereJS per documentLegacy queries / learning only
$expr + operatorsNative expression evalField math / field-vs-field filters
Plain query opsCan use indexesSimple equality / range filters

Narrow the set first with indexed filters when possible, then apply expression logic. Avoid $where on large collections.

Key Takeaways

  • Role: JavaScript boolean filter inside find().
  • this: current document fields (this.price).
  • Prefer: $expr with native operators for new code.
  • Safety: never concatenate user input into $where.

One line: learn $where to read legacy queries—write new filters with $expr instead.

Frequently Asked Questions

$where runs a JavaScript expression against each document in a find() query. The expression must return true to keep the document. Inside the script, this refers to the current document.
Pass a string: { $where: "this.qty * this.price > 1000" } or a function: { $where: function() { return this.qty * this.price > 1000; } }. Use it inside find().
No for new work. Prefer $expr with aggregation operators such as $multiply and $gt. $where is slower, hard to index, and risky if built from user input.
this is the current document. Read fields as this.fieldName, for example this.price or this.qty.
Use $expr: { $expr: { $gt: [ { $multiply: ["$qty", "$price"] }, 1000 ] } }. Native operators avoid arbitrary JavaScript and usually perform better.
Generally no. MongoDB must evaluate the JavaScript per document. Prefer indexed query operators or $expr patterns that the planner can optimize.

Next: $year

Extract the calendar year from a BSON date in an aggregation pipeline.

$year tutorial →

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.

9 people found this page helpful