2.2 Query Selectors & Filter Operators

Key Takeaways

  • Comparison operators ('$eq', '$ne', '$gt', '$gte', '$lt', '$lte', '$in', '$nin') filter scalar values and ranges, with '$in' optimizing matching across candidate sets.
  • Implicit '$and' applies across distinct fields in a single query document, whereas an explicit '$and' array is required for multiple conditions on the same field or combining '$or' expressions.
  • Element operators evaluate schema structure: '$exists' tests field presence, while '$type' matches BSON types via string aliases or numeric codes.
  • Querying '{ field: null }' matches both explicit null values and missing fields; matching only literal nulls requires '{ field: { $type: "null" } }'.
  • Evaluation operators include '$regex' for pattern matching, '$mod' for remainder arithmetic, and '$expr' to compare two fields within the same document using aggregation expressions.
Last updated: September 2026

Query Selectors & Filter Operators

Retrieving data from MongoDB collections is accomplished using the db.collection.find() and db.collection.findOne() methods. The first argument to these methods is the query filter document—a JSON/BSON object that specifies the criteria documents must satisfy to be returned in the result set.

MongoDB Query Language (MQL) categorizes query operators into four fundamental groups:

  1. Comparison Operators
  2. Logical Operators
  3. Element Operators
  4. Evaluation Operators

Comparison Operators

Comparison operators evaluate field values against target literals, ranges, or sets of candidate values.

OperatorNameSyntax ExampleDescription
$eqEqual To{ age: { $eq: 25 } }Matches values equal to a specified value (implicit in { age: 25 }).
$neNot Equal To{ status: { $ne: "ARCHIVED" } }Matches values not equal to the specified value (also matches docs missing the field).
$gtGreater Than{ score: { $gt: 85 } }Matches values strictly greater than the specified value.
$gteGreater Than or Equal{ price: { $gte: 100 } }Matches values greater than or equal to the specified value.
$ltLess Than{ stock: { $lt: 10 } }Matches values strictly less than the specified value.
$lteLess Than or Equal{ rating: { $lte: 3.5 } }Matches values less than or equal to the specified value.
$inIn Array / Set{ tier: { $in: ["Gold", "Platinum"] } }Matches any field value that equals at least one value in the specified array.
$ninNot In Array / Set{ tier: { $nin: ["Bronze", "Suspended"] } }Matches field values not present in the array (and docs lacking the field).

Range Queries on Numeric and Date Fields

Combining range operators on a single field creates bounded intervals:

// Find active subscriptions renewing in September 2026
db.subscriptions.find({
  status: "ACTIVE",
  renewal_date: {
    $gte: ISODate("2026-09-01T00:00:00Z"),
    $lt: ISODate("2026-10-01T00:00:00Z")
  }
});

$in vs. $or for Value Matching

When checking whether a single field matches any value from a set of candidates, always prefer $in over multiple $or equality clauses. The $in operator is syntactically cleaner and allows the query planner to perform optimized B-tree index lookups.

// PREFERRED: Efficient index scan using $in
db.inventory.find({ category: { $in: ["apparel", "footwear", "accessories"] } });

// AVOID: Verbose and slower $or equivalent
db.inventory.find({
  $or: [
    { category: "apparel" },
    { category: "footwear" },
    { category: "accessories" }
  ]
});

Logical Operators: Implicit vs. Explicit $and, $or, $nor, $not

Logical operators allow developers to combine multiple filter expressions into complex boolean conditions.

+-------------------------------------------------------------------------+
|                        MongoDB Logical Operators                        |
|                                                                         |
|  - $and : Joins query clauses with logical AND (all must match).        |
|  - $or  : Joins query clauses with logical OR (at least one must match).|
|  - $nor : Joins query clauses with logical NOR (all must fail).         |
|  - $not : Inverts the effect of a query predicate on a specific field.  |
+-------------------------------------------------------------------------+

1. Implicit $and vs. Explicit $and

By default, MongoDB applies an implicit $and across all comma-separated field criteria specified in a single query document:

// Implicit $and: All three conditions must be satisfied
db.employees.find({
  department: "Engineering",
  is_active: true,
  salary: { $gte: 120000 }
});

When is an Explicit $and Required?

An explicit $and operator takes an array of expression documents ({ $and: [ { <clause1> }, { <clause2> } ] }) and is strictly required in two scenarios:

  1. Multiple conditions on the same field using the same operator: In JavaScript/JSON, object keys must be unique. Writing { price: { $ne: 50 }, price: { $ne: 100 } } causes the second key to overwrite the first. To enforce both, you must use explicit $and.
  2. Combining multiple $or expressions: If a query needs to satisfy (A or B) AND (C or D), an explicit $and array is necessary.
// Scenario 1: Multiple conditions targeting the same field/operator
db.products.find({
  $and: [
    { tags: { $ne: "clearance" } },
    { tags: { $ne: "refurbished" } }
  ]
});

// Scenario 2: Combining two independent $or clauses
db.orders.find({
  $and: [
    { $or: [{ status: "PENDING" }, { status: "PROCESSING" }] },
    { $or: [{ total: { $gte: 500 } }, { is_priority_customer: true }] }
  ]
});

2. The $or Operator

$or performs a logical OR operation on an array of two or more expressions. MongoDB can utilize independent indexes on each clause of an $or expression.

db.users.find({
  $or: [
    { role: "ADMIN" },
    { access_level: { $gte: 9 } }
  ]
});

3. The $nor Operator

$nor returns documents that fail all query clauses in the array (or where the targeted fields do not exist).

// Returns products that are NOT out of stock AND NOT discontinued
db.products.find({
  $nor: [
    { in_stock: false },
    { is_discontinued: true }
  ]
});

4. The $not Operator

$not performs a logical NOT on a specific field operator expression, matching documents that do not match the expression (including documents where the field is missing entirely):

// Matches documents where price is NOT greater than 50 (i.e. price <= 50 or price is missing)
db.inventory.find({
  price: { $not: { $gt: 50 } }
});

Element Operators: $exists and $type

Because MongoDB collections have flexible schemas, documents within the same collection may have different fields or data types. Element operators inspect schema presence and BSON type metadata.

1. The $exists Operator

The $exists operator takes a boolean (true or false) to determine whether a specific field key exists in a document.

// Find users who have an optional secondary phone field
db.users.find({ secondary_phone: { $exists: true } });

// Find users who do NOT have a secondary phone field
db.users.find({ secondary_phone: { $exists: false } });

2. The Null vs. Missing Field Trap (Critical Exam Topic)

A major trap on the certification exam is querying for null values:

// Query A: Matches documents where 'middle_name' is null OR 'middle_name' does NOT exist!
db.contacts.find({ middle_name: null });

// Query B: Matches documents where 'middle_name' exists AND holds literal BSON null
db.contacts.find({
  middle_name: { $exists: true, $type: "null" }
});

// Query C: Matches documents where 'middle_name' is completely missing from the schema
db.contacts.find({
  middle_name: { $exists: false }
});
Document{ field: null }{ field: { $exists: true } }{ field: { $type: "null" } }
{ _id: 1, field: "Alex" }❌ No✅ Yes❌ No
{ _id: 2, field: null }Yes✅ YesYes
{ _id: 3 } (missing field)Yes❌ No❌ No

3. The $type Operator

The $type operator selects documents where the value of a field is an instance of a specified BSON type, specified by string alias (e.g., "string", "decimal", "int", "objectId", "array") or numeric type code.

// Find documents where 'zip_code' was incorrectly stored as a Number rather than a String
db.addresses.find({
  zip_code: { $type: "number" } // matches double, int32, int64, decimal128
});

// Find documents where 'balance' is strictly a Decimal128
db.accounts.find({
  balance: { $type: 19 } // numeric code 19 = decimal
});

Evaluation Operators: $regex, $mod, and $expr

Evaluation operators execute advanced mathematical, pattern matching, or expression evaluations during query processing.

1. The $regex Operator

$regex provides regular expression pattern matching for string fields. It supports standard PCRE regular expressions and optional flags (i for case-insensitivity, m for multiline, s for dotall, x for extended whitespace).

// Syntax 1: Using $regex operator object with options
db.customers.find({
  email: { $regex: "@gmail\\.com$", $options: "i" }
});

// Syntax 2: Using JavaScript RegExp literal
db.customers.find({
  email: /@gmail\.com$/i
});

Performance Note: Prefix regular expressions (e.g., /^Acme/) can effectively utilize B-tree indexes for fast prefix range scans. Case-insensitive regexes (/i) or non-prefix regexes (/.*corp/) cannot use standard indexes efficiently and cause full collection scans (COLLSCAN).

2. The $mod Operator

$mod performs modulo arithmetic on numeric fields, matching documents where the field value divided by a divisor yields a specified remainder: { field: { $mod: [ divisor, remainder ] } }.

// Find orders where the quantity is an even number (quantity % 2 == 0)
db.orders.find({
  quantity: { $mod: [ 2, 0 ] }
});

3. The $expr Operator: Intra-Document Field Comparisons

In standard MQL query filters, field values are compared against constant literal values. You cannot compare two different fields within the same document using standard comparison operators because the right-hand value is treated as a literal string.

// WRONG: This searches for documents where 'spent' is greater than the literal string "$budget"!
db.projects.find({ spent: { $gt: "$budget" } });

The $expr operator solves this by enabling the use of Aggregation Expressions within standard find() query filters. Inside $expr, field paths prefixed with $ refer to the value of that field in the current document.

Syntax

db.collection.find({
  $expr: { <aggregation expression> }
})

Example 1: Comparing Two Fields in the Same Document

// Find projects where the actual 'spent' exceeds the allocated 'budget'
db.projects.find({
  $expr: {
    $gt: [ "$spent", "$budget" ]
  }
});

Example 2: Mathematical Computations Inside Query Filter

// Find items where the discounted price (price * 0.8) is still greater than 100
db.products.find({
  $expr: {
    $gt: [
      { $multiply: [ "$price", 0.8 ] },
      100
    ]
  }
});

Example 3: Conditional Logic with $cond Inside $expr

// Find users whose spent amount exceeds their dynamic threshold based on tier
db.users.find({
  $expr: {
    $gt: [
      "$total_spent",
      {
        $cond: {
          if: { $eq: [ "$tier", "VIP" ] },
          then: 5000,
          else: 1000
        }
      }
    ]
  }
});

Exam Tip: Whenever an exam question asks to "compare two fields in the same document" or "filter documents where fieldA is greater than fieldB", the correct answer always involves $expr.

Loading diagram...
MQL Query Selector Taxonomy
Test Your Knowledge

An e-commerce database needs to query a collection named 'sales' to find all transactions where the final 'total_revenue' is strictly less than the calculated 'target_quota' field within the same document. Which MQL query correctly accomplishes this?

A
B
C
D
Test Your Knowledge

A collection contains three documents: { _id: 1, tag: null }, { _id: 2 }, and { _id: 3, tag: "promo" }. Which query will return ONLY document { _id: 1 }?

A
B
C
D
Test Your Knowledge

Under which of the following circumstances is an explicit '$and' operator mandatory in a MongoDB find query filter rather than relying on implicit logical AND?

A
B
C
D
Test Your Knowledge

How does MongoDB evaluate the '$in' operator when applied to a field that contains an array of scalar values, such as 'db.inventory.find({ tags: { $in: ["red", "blue"] } })'?

A
B
C
D