Query operators

MongoDB · Essentials · 10 min

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, $nor take an array of filters; $not negates one operator expression. { $or: [{ vip: true }, { total: { $gt: 100 } }] }.
  • Element: $exists: true/false tests presence; $type: "string" tests the BSON type.
  • Evaluation: $regex for patterns, $expr to 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: 3

Remember

  • 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.

Check yourself

  1. Which filter finds orders with status "paid" or "shipped"?
  2. A collection has documents with and without a color field. What does { color: { $ne: "red" } } return?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: www.mongodb.com/docs/manual/reference/operator/query/