MongoDBAll Query Operators Reference

Query Operators

Query operators live inside the filter document you pass to find(), updateOne(), deleteMany(), and friends. They're grouped by purpose: comparison, logical, element, and evaluation operators. Together they cover almost every filtering need without writing raw JavaScript.

Comparison Operators

Operator

Meaning

$eq

Equal to

$ne

Not equal to

$gt / $gte

Greater than / greater than or equal to

$lt / $lte

Less than / less than or equal to

$in

Matches any value in a given array

$nin

Matches none of the values in a given array

$eq, $ne

JS
db.products.find({ category: { $eq: "widgets" } })   // same as { category: "widgets" }
db.products.find({ category: { $ne: "widgets" } })   // everything except widgets

$gt, $gte, $lt, $lte — ranges

JS
db.products.find({ price: { $gt: 10 } })
db.products.find({ price: { $gte: 10, $lte: 50 } })   // range: 10 <= price <= 50
db.orders.find({ createdAt: { $lt: ISODate("2024-01-01") } })

$in, $nin

JS
db.products.find({ category: { $in: ["widgets", "gadgets"] } })
db.products.find({ status: { $nin: ["discontinued", "recalled"] } })
Tip
$in with an array of values is almost always faster and cleaner than $or-ing several equality checks on the same field — MongoDB can use a single index scan for $in across multiple values.
Logical Operators

Operator

Meaning

$and

All conditions must be true

$or

At least one condition must be true

$nor

None of the conditions may be true

$not

Negates a single condition (applied to one operator expression)

$and — implicit vs explicit

JS
// Implicit AND — separate fields in the same document are already ANDed
db.products.find({ category: "widgets", price: { $lt: 20 } })

// Explicit $and — required when combining multiple conditions on the SAME field
db.products.find({
  $and: [
    { price: { $gte: 10 } },
    { price: { $lte: 50 } }
  ]
})

$or, $nor

JS
db.products.find({
  $or: [{ category: "widgets" }, { price: { $lt: 5 } }]
})

db.products.find({
  $nor: [{ category: "widgets" }, { discontinued: true }]
})
// matches products that are NEITHER widgets NOR discontinued

$not — negating a single condition

JS
db.products.find({ price: { $not: { $gt: 100 } } })
// matches price <= 100 OR price missing OR price not a comparable type
// (different from { price: { $lte: 100 } }, which requires the field to exist and be comparable)
Note
Multiple key-value pairs at the top level of a filter document are already an implicit $and. You only need an explicit $and when you must apply two or more conditions to the same field, since a plain object can't repeat a key twice.
Element Operators

Operator

Meaning

$exists

Matches documents that have (or lack) a given field

$type

Matches documents where a field is a specific BSON type

$exists

JS
db.users.find({ middleName: { $exists: true } })    // field is present (even if null)
db.users.find({ middleName: { $exists: false } })   // field is absent entirely

$type

JS
db.products.find({ price: { $type: "string" } })   // catches price stored as a string by mistake
db.products.find({ price: { $type: ["int", "double", "decimal"] } })  // any numeric type
Evaluation Operators

Operator

Meaning

$regex

Pattern-matches a string field

$expr

Allows aggregation expressions inside a query filter, e.g. comparing two fields

$mod

Matches when a field, divided by a divisor, has a given remainder

$where

Runs arbitrary JavaScript per document — avoid in modern code

$regex — pattern matching strings

JS
db.users.find({ email: { $regex: /^alice/, $options: "i" } })
db.users.find({ email: /@example\.com$/ })   // native regex literal works directly, no $regex needed

$expr — comparing two fields in the same document

JS
// Find orders where the amount paid is less than the total owed
db.orders.find({ $expr: { $lt: ["$amountPaid", "$total"] } })

$mod

JS
// Even-numbered batch ids
db.batches.find({ batchId: { $mod: [2, 0] } })
Warning
Avoid $where in new code. It executes arbitrary JavaScript per document on the server — far slower than native operators, unable to use indexes, and a historical injection surface if any part of the JS string comes from user input. Almost anything you'd reach for $where to do can be expressed with $expr and native aggregation operators instead.
Combining Operators

A realistic combined filter

JS
db.products.find({
  category: { $in: ["widgets", "gadgets"] },
  price: { $gte: 5, $lte: 100 },
  stock: { $gt: 0 },
  $or: [{ featured: true }, { rating: { $gte: 4.5 } }]
})
  • Comparison: $eq, $ne, $gt/$gte, $lt/$lte, $in, $nin.

  • Logical: $and, $or, $nor, $not — top-level fields are already ANDed implicitly.

  • Element: $exists, $type.

  • Evaluation: $regex, $expr, $mod — avoid $where.