Real queries need ranges, alternatives and missing-field checks, not just equality.
Operators start with $ and go where a value would: { age: { $gte: 18, $lt: 65 } } means 18 to 64.
- Comparison:
$eq,$ne,$gt,$gte,$lt,$lte,$in,$nin.{ status: { $in: ["paid", "shipped"] } }is a compact OR on one field. - Logical:
$or,$and,$nortake an array of filters;$notnegates one operator expression.{ $or: [{ vip: true }, { total: { $gt: 100 } }] }. - Element:
$exists: true/falsetests presence;$type: "string"tests the BSON type. - Evaluation:
$regexfor patterns,$exprto compare two fields of the same document, e.g.{ $expr: { $gt: ["$spent", "$budget"] } }.
You rarely need $and explicitly, because listing several fields already ANDs them. You do need it when combining two $or clauses, since a document can't have two $or keys.
Watch the semantics of negation: $ne and $nin also match documents where the field is missing, and they usually can't use an index efficiently. A case-insensitive or unanchored $regex like /smith/i scans every value; only a prefix regex such as /^smi/ (case-sensitive) can use an index range.
Example
db.orders.insertMany([
{ n: 1, status: "paid", total: 40, coupon: "FALL" },
{ n: 2, status: "shipped", total: 150 },
{ n: 3, status: "new", total: 90, spent: 120, budget: 100 }
])
db.orders.find({ total: { $gte: 50, $lt: 200 } }, { _id: 0, n: 1 })
// [ { n: 2 }, { n: 3 } ]
db.orders.find({ $or: [{ status: "paid" }, { total: { $gt: 100 } }] }, { _id: 0, n: 1 })
// [ { n: 1 }, { n: 2 } ]
db.orders.find({ coupon: { $exists: false } }, { _id: 0, n: 1 }) // n: 2 and 3
db.orders.find({ status: { $ne: "paid" } }, { _id: 0, n: 1 }) // n: 2 and 3
db.orders.find({ $expr: { $gt: ["$spent", "$budget"] } }, { _id: 0, n: 1 }) // n: 3Remember
- Operators go in the value position: { field: { $op: value } }
- $in is OR over one field; $or combines whole sub-filters
- $exists and $type test presence and BSON type; $expr compares fields
- $ne/$nin also match missing fields and are index-unfriendly
Watch out for
- Writing { age: { $gt: 18 }, age: { $lt: 30 } }: duplicate keys in a JS object keep only the last; put both operators in one object.