Query Operators & Filtering
Checking access...
MongoDB’s query language supports a rich set of operators for filtering documents by any condition imaginable — comparisons, logical combinations, array queries, regular expressions, and more.
Comparison Operators
// Sample data[ { name: "Alice", age: 30, salary: 70000 }, { name: "Bob", age: 25, salary: 50000 }, { name: "Charlie", age: 35, salary: 90000 }, { name: "Diana", age: 28, salary: 65000 },]| Operator | Meaning | Example |
|---|---|---|
$eq | Equal to | { age: { $eq: 30 } } |
$ne | Not equal to | { age: { $ne: 30 } } |
$gt | Greater than | { age: { $gt: 30 } } |
$gte | Greater than or equal | { age: { $gte: 30 } } |
$lt | Less than | { age: { $lt: 30 } } |
$lte | Less than or equal | { age: { $lte: 30 } } |
$in | In array | { age: { $in: [25, 30, 35] } } |
$nin | Not in array | { age: { $nin: [20, 40] } } |
Shorthand for Equality
// These are equivalent:{ age: { $eq: 30 } }{ age: 30 } // ShorthandCompound Range Queries
// Age between 25 and 35 inclusivedb.users.find({ age: { $gte: 25, $lte: 35 } });
// Salary above 60k and below 80k (exclusive)db.users.find({ salary: { $gt: 60000, $lt: 80000 } });Using $in and $nin
// Users in specific age bracketsdb.users.find({ age: { $in: [25, 30, 35] } });
// Exclude certain rolesdb.users.find({ role: { $nin: ["banned", "deleted"] } });Logical Operators
$and
All conditions must be true:
// Find users over 30 who earn more than 60kdb.users.find({ $and: [ { age: { $gt: 30 } }, { salary: { $gt: 60000 } }, ]});
// Shorthand (implicit AND)db.users.find({ age: { $gt: 30 }, salary: { $gt: 60000 } });Use explicit $and when you need multiple conditions on the same field:
// Age between 25 and 35db.users.find({ $and: [ { age: { $gte: 25 } }, { age: { $lte: 35 } }, ]});
// Simpler equivalentdb.users.find({ age: { $gte: 25, $lte: 35 } });$or
At least one condition must be true:
// Users who are under 25 OR over 40db.users.find({ $or: [ { age: { $lt: 25 } }, { age: { $gt: 40 } }, ]});
// Users who are named Alice OR earn more than 80kdb.users.find({ $or: [ { name: "Alice" }, { salary: { $gt: 80000 } }, ]});$nor
None of the conditions must be true (opposite of $or):
// Not over 30 AND not earning more than 70kdb.users.find({ $nor: [ { age: { $gt: 30 } }, { salary: { $gt: 70000 } }, ]});$not
Negates a query operator:
// Age is NOT greater than 30 (i.e., age <= 30)db.users.find({ age: { $not: { $gt: 30 } } });
// Name does NOT match the regex patterndb.users.find({ name: { $not: /^A/ } });Element Operators
$exists
Check if a field exists (or doesn’t):
// Users who have a "phone" fielddb.users.find({ phone: { $exists: true } });
// Users WITHOUT a "phone" fielddb.users.find({ phone: { $exists: false } });$type
Match documents where a field is of a specific BSON type:
// Age field is a number (double or int)db.users.find({ age: { $type: "number" } });
// Name field is a stringdb.users.find({ name: { $type: "string" } });
// Multiple typesdb.users.find({ age: { $type: ["int", "double"] } });BSON type codes: "string", "number", "object", "array", "bool", "null", "int", "double", "date", "objectId", etc.
$expr
Use aggregation expressions within queries (useful for comparing fields):
// Find documents where price with tax exceeds 100db.products.find({ $expr: { $gt: [{ $add: ["$price", "$tax"] }, 100] }});
// Find users whose account balance is below the minimumdb.accounts.find({ $expr: { $lt: ["$balance", "$minimumBalance"] }});Array Operators
// Sample datadb.inventory.insertMany([ { item: "laptop", tags: ["electronics", "computers", "portable"], price: 999 }, { item: "phone", tags: ["electronics", "mobile"], price: 699 }, { item: "book", tags: ["education"], price: 29 }, { item: "desk", tags: ["furniture", "office"], price: 399 },]);$all
Matches arrays that contain all specified elements:
// Items tagged as BOTH electronics AND computersdb.inventory.find({ tags: { $all: ["electronics", "computers"] } });// Returns: laptop$elemMatch
Matches if at least one array element satisfies all conditions:
// Sample: products with ratings array[ { name: "Laptop", ratings: [{ score: 5, user: "Alice" }, { score: 3, user: "Bob" }] }, { name: "Phone", ratings: [{ score: 4, user: "Alice" }] },]
// Find products with at least one rating of 5 from Alicedb.products.find({ ratings: { $elemMatch: { score: 5, user: "Alice" } }});Array Position Access
// First tagdb.inventory.find({ "tags.0": "electronics" });
// Array lengthdb.inventory.find({ tags: { $size: 3 } });
// Array index in projectiondb.inventory.find({}, { tags: { $slice: 2 } }); // First 2 tagsdb.inventory.find({}, { tags: { $slice: -1 } }); // Last tag$elemMatch in Projection
// Return only the matching array elementdb.products.find( { ratings: { $elemMatch: { score: { $gte: 4 } } } }, { ratings: { $elemMatch: { score: { $gte: 4 } } } });Regular Expressions
Regex queries for pattern matching:
// Names starting with "A"db.users.find({ name: /^A/ });
// Names containing "lice" (case-insensitive)db.users.find({ name: /lice/i });
// Emails from gmaildb.users.find({ email: /@gmail\.com$/ });
// Using $regex operator (more explicit)db.users.find({ name: { $regex: "^A", $options: "i" } });Performance note: Regex without anchor (^) or using case-insensitive flags (i) cannot use indexes efficiently. Use with caution on large collections.
Querying Embedded Documents
// Sample documents[ { name: "Alice", address: { city: "London", country: "UK", zip: "EC1A 1BB" } }, { name: "Bob", address: { city: "NYC", country: "USA", zip: "10001" } },]Exact Match on Embedded Document
// Match the entire embedded document (order matters!)db.users.find({ address: { city: "London", country: "UK", zip: "EC1A 1BB" } });Dot Notation (Field within Embedded Document)
// Match a specific field within an embedded documentdb.users.find({ "address.city": "London" });
// Multiple conditions on embedded fieldsdb.users.find({ "address.city": "London", "address.country": "UK",});Null and Missing Values
// Field is null (either explicitly null or missing)db.users.find({ phone: null });
// Field is explicitly null (not missing)db.users.find({ phone: { $type: "null" } });
// Field exists AND is nulldb.users.find({ phone: { $eq: null, $exists: true } });Putting It All Together
// Complex query: Find premium electronics under $500// that are in stock and have at least 4-star reviewsdb.products.find({ category: "electronics", price: { $lte: 500 }, stock: { $gt: 0 }, $or: [ { "rating.average": { $gte: 4 } }, { "rating.count": { $gte: 100 } }, ], tags: { $all: ["premium", "new"] },}).sort({ price: 1 }).limit(10);Quick Reference
// Comparison{ field: { $gt: 10, $lte: 100 } }{ field: { $in: [1, 2, 3] } }{ field: { $nin: [4, 5, 6] } }
// Logical{ $and: [{ field1: val }, { field2: val }] }{ $or: [{ field1: val }, { field2: val }] }{ $nor: [{ field1: val }, { field2: val }] }{ field: { $not: { $gt: 10 } } }
// Element{ field: { $exists: true } }{ field: { $type: "string" } }
// Array{ array: { $all: [val1, val2] } }{ array: { $elemMatch: { field: val } } }{ array: { $size: 3 } }
// Regex{ field: /^pattern/i }{ field: { $regex: "pattern", $options: "i" } }
// Embedded{ "embedded.field": value }Practice Exercises
Product filtering: Given a
productscollection withprice,category,rating,inStock,tags, write queries to: find products under $50 with 4+ rating, find items tagged “sale” AND “clearance”, find products in “electronics” OR “computers” that are in stock.User analytics: Write queries to find users who registered in the last 30 days AND have not logged in, users whose name starts with “M” and are over 40, and users who have a “bio” field that contains “developer” (case-insensitive).
Array matching: Create a collection of blog posts with a
commentsarray (each comment hasuser,text,likes). Find posts where a single comment has more than 10 likes from user “Alice”.Regex search: Build a search query that matches products whose name contains the search term, case-insensitive. Then add a condition to also match products whose description contains the term.