Query Operators: A Complete Guide to the 30+ Operator

Query operators are at the heart of MongoDB queries—mastering 30+ operators can handle 90% of query scenarios.

This course provides a systematic overview of the usage, combinations, and performance optimization techniques for all query operators.

1. What You'll Learn


2. A Data Analyst’s True Story

(1) Pain Point: Complex queries require nested if-else statements

Diana is an e-commerce data analyst who needs to find products that meet the following criteria: "price 100–500, inventory > 0, tags include 'bestseller' or 'new,' and rating >= 4":

JAVASCRIPT
// ❌ Counterexample:Query everything first, then filter
const allProducts = await Product.find();
const filtered = allProducts.filter(p =>
  p.price >= 100 && p.price <= 500 &&
  p.stock > 0 &&
  (p.tags.includes('bestseller') || p.tags.includes('new')) &&
  p.rating >= 4
);
// 100,000 Data Points, Return only 100 items,But after checking all of them

(2) Solutions for MongoDB Operators

JAVASCRIPT
// ✅ Correct Example:A single query,Combining Operators
const products = await Product.find({
  price: { $gte: 100, $lte: 500 },
  stock: { $gt: 0 },
  tags: { $in: ['bestseller', 'new'] },
  rating: { $gte: 4 }
});
// Database-Level Filtering,1 million -> 100 items,Performance ↑1000x

100%
graph TB
    A[Query Operators] --> B[Comparison Operators<br/>$eq/$gt/$lt]
    A --> C[Logical Operators<br/>$and/$or/$not]
    A --> D[Element Operators<br/>$exists/$type]
    A --> E[Array Operators<br/>$all/$size/$elemMatch]
    A --> F[Evaluation Operator<br/>$regex/$expr/$mod]

    style B fill:#d4edda
    style E fill:#d4edda

3. Comparison Operators

Concept Overview: Comparison operators are the most basic and commonly used category of query operators, supporting operations such as equality, inequality, greater than, less than, range, and multi-value matching. The eight comparison operators cover 90% of everyday query scenarios, with $in and range queries (the $gt/$gte/$lt/$lte combination) being the most frequently used.

How It Works: Comparison operators act on a single field; MongoDB translates them into an index scan or a full-table scan. $eq and $in are the most index-friendly (supporting exact matches or multi-value scans); range queries ($gt/$lt) can also use indexes, but efficiency depends on the range size. $ne and $nin are not index-friendly—because documents that “are not equal to a certain value” may be scattered throughout the index.

100%
graph TB
    A[Comparison Operators] --> B[Equivalence Class<br/>$eq / $ne]
    A --> C[Scope Class<br/>$gt / $gte / $lt / $lte]
    A --> D[Multi-valued types<br/>$in / $nin]
    
    B --> B1[Index Friendliness: $eq ✅ / $ne ⚠️]
    C --> C1[Index Friendliness: ✅ Range Scan]
    D --> D1[Index Friendliness: $in ✅ / $nin ⚠️]
Operator Meaning Equivalent SQL Index-Friendly Frequency of Use
$eq Equals = value ⭐⭐⭐ (Default)
$ne Not equal to != value ⚠️
$gt Greater than > value ⭐⭐
$gte Greater than or equal to >= value ⭐⭐⭐
$lt Smaller than < value ⭐⭐
$lte Less than or equal to <= value ⭐⭐⭐
$in Included in the array IN (...) ⭐⭐⭐
$nin Not included NOT IN (...) ⚠️

(1) Complete List

Operator Meaning Example
$eq equals { price: { $eq: 599 } }
$ne is not equal to { status: { $ne: 'deleted' } }
$gt Greater than { age: { $gt: 18 } }
$gte Greater than or equal to { rating: { $gte: 4 } }
$lt Smaller than { stock: { $lt: 10 } }
$lte Less than or equal to { discount: { $lte: 0.5 } }
$in Included in the array { category: { $in: ['A', 'B'] } }
$nin Not included in the array { status: { $nin: ['deleted', 'banned'] } }

▶ Example 1: Comparison Operators in Practice

JAVASCRIPT
// === Price Range ===
db.products.find({
  price: { $gte: 100, $lte: 500 }   // 100 <= price <= 500
});

// === Multi-value matching ===
db.products.find({
  category: { $in: ['Electronics', 'Books'] }
});

// === Exclude Specific Values ===
db.users.find({
  role: { $nin: ['banned', 'deleted'] }
});

4. Logical Operators

Concept Explanation: Logical operators combine multiple query conditions to implement AND/OR/NOT logic. The most common logic in MongoDB is implicit AND—{ a: 1, b: 2 } is equivalent to { $and: [{ a: 1 }, { b: 2 }] }. Explicit $and must only be used when there are "multiple conditions on the same field" (e.g., { $and: [{ price: { $gte: 100 } }, { price: { $lte: 500 } }] }).

How It Works: $and requires that all sub-conditions be satisfied simultaneously; the MongoDB optimizer will prioritize executing the most selective condition. $or requires that any one sub-condition be satisfied; MongoDB executes queries for each sub-condition independently and then merges the result sets—which means it is best to have an index on each sub-condition in $or, otherwise multiple full table scans will be triggered.

100%
graph TB
    A[Logical Operators] --> B[Implicit AND<br/>{ a: 1, b: 2 }<br/>Most Commonly Used ⭐⭐⭐]
    A --> C[$and<br/>Multiple Conditions for the Same Field]
    A --> D[$or<br/>Any that satisfies ⭐⭐]
    A --> E[$not<br/>Negate ⭐]
    A --> F[$nor<br/>None of the conditions are met]

    style B fill:#d4edda
Operator Meaning Equivalent SQL Notes
Implicit AND Comma-separated WHERE a=1 AND b=2 Most Common Notation
$and Explicit AND WHERE (a=1 AND b=2) Must use for multiple conditions on the same field
$or Any one that satisfies WHERE a=1 OR b=2 Each subcondition should have an index
$not Not compatible WHERE NOT (cond) Often used in conjunction with $regex
$nor None met WHERE NOT (a=1 OR b=2) Underused

(1) Complete List

Operator Meaning
$and All met
$or Any that satisfies
$not Not satisfied
$nor None met

▶ Example 2: Practical Application of Logical Operators

JAVASCRIPT
// === Implicit $and ===
db.products.find({
  category: 'Electronics',
  stock: { $gt: 0 }
  // equivalent to { $and: [{ category: 'Electronics' }, { stock: { $gt: 0 } }] }
});

// === Explicit $and(Multiple Conditions for the Same Field)===
db.products.find({
  $and: [
    { price: { $gte: 100 } },
    { price: { $lte: 500 } }
    // Must use $and,Because you cannot specify multiple conditions for the same field directly
  ]
});

// === $or ===
db.products.find({
  $or: [
    { category: 'Electronics' },
    { tags: 'bestseller' }
  ]
});

// === $nor(None of them match)===
db.products.find({
  $nor: [
    { category: 'Books' },
    { stock: 0 }
  ]
});
// Return is neither Books Categories、Items Currently in Stock

// === Nested Logic ===
db.products.find({
  $and: [
    { category: 'Electronics' },
    {
      $or: [
        { tags: 'bestseller' },
        { rating: { $gte: 4.5 } }
      ]
    }
  ]
});

5. Element Operators

Concept Explanation: Element operators check the existence and type of fields in a document—$exists determines whether a field exists, and $type determines the BSON type of a field. These two operators are crucial for data quality checks and cleaning up dirty data: $exists can identify documents with missing required fields, and $type can identify fields with incorrect types (such as price being incorrectly stored as a string instead of a number).

How It Works: $exists: true matches all documents that contain the specified field (including documents where the field value is null), while $exists: false matches documents that do not contain that field. $type matches based on BSON type codes or type names and supports array formats (e.g., { price: { $type: ["number", "decimal"] } } matches Double or Decimal128).

Operator Meaning Typical Scenarios
$exists: true Field exists Find products with a "discount" field
$exists: false Field does not exist Find users with missing email addresses
$type: "string" Field type is string Find documents where "price" was incorrectly stored as a string
$type: ["number", "decimal"] One of several types Find documents where price is of any numeric type

(1) $exists checks whether a field exists

JAVASCRIPT
// === Field exists ===
db.products.find({ discount: { $exists: true } });
// Have discount Products in the Field

// === Field does not exist ===
db.users.find({ lastLoginAt: { $exists: false } });
// Users who have never logged in

// === In conjunction with other conditions ===
db.products.find({
  discount: { $exists: true, $ne: null }
});
// Have discount Let's not worry about that for now null

(2) $type: Check the field type

JAVASCRIPT
// === Type Code Reference ===
// 1: Double, 2: String, 3: Object, 4: Array
// 5: Binary, 7: ObjectId, 8: Boolean, 9: Date
// 10: Null, 16: Int32, 18: Long, 19: Decimal128

// === String Type ===
db.products.find({ sku: { $type: "string" } });

// === Numeric Types(Various)===
db.products.find({ price: { $type: ["number", "decimal"] } });
// Double or Decimal128

// === Practical Applications:Identify fields with type errors ===
db.products.find({ price: { $type: "string" } });
// Find price Documents in Which Fields Were Incorrectly Stored as Strings(Frequently Asked Questions About Data Migration)

▶ Example 3: Element Operators in Action

JAVASCRIPT
// === Find "dirty" data with missing fields ===
db.users.find({
  $or: [
    { email: { $exists: false } },
    { username: { $exists: false } }
  ]
});

// === Type Correction ===
db.products.find({ price: { $type: "string" } }).forEach(doc => {
  db.products.updateOne(
    { _id: doc._id },
    { $set: { price: NumberDecimal(doc.price) } }
  );
});

6. Array Operators

Concept Explanation: Array operators are the most unique category of MongoDB query operators, specifically designed to handle array fields—$all matches arrays containing all specified elements, $size matches arrays of a specific length, and $elemMatch matches a single element in an array that satisfies multiple conditions simultaneously. Among these, $elemMatch is the most error-prone and also the most important array operator.

How It Works: By default, MongoDB’s array queries use “any element match”—{ tags: "5g" } matches documents where the tags array contains “5g.” However, in multi-condition queries, { "reviews.rating": { $gte: 4 }, "reviews.content": /good/ } may match documents with different array elements (one comment has a high rating, while another contains a keyword). $elemMatch solves this problem—it ensures that the same array element satisfies all conditions simultaneously.

100%
graph TB
    A[Array Operators] --> B[$all<br/>Includes all specified elements]
    A --> C[$size<br/>Exact Match for Array Length]
    A --> D[$elemMatch<br/>Multi-Condition Matching for the Same Element<br/>⭐ Most important]

    D --> D1[Dot notation<br/>Different elements may match]
    D --> D2[$elemMatch<br/>The same element must match]

    style D fill:#d4edda
    style D2 fill:#d4edda
Operator Meaning Syntax Notes
$all Includes all specified elements { tags: { $all: ["5g", "amoled"] } } Order does not matter
$size Exact match for array length { tags: { $size: 3 } } Does not support ranges; use $expr
$elemMatch Multiple-condition matching for the same element { reviews: { $elemMatch: { ... } } } Distinction from dot notation

(1) $all matches all elements

JAVASCRIPT
// === Must include all specified elements(Order does not matter)===
db.products.find({ tags: { $all: ['5g', 'amoled'] } });
// Includes both 5g and amoled Products

// === equivalent to $and ===
db.products.find({
  $and: [
    { tags: '5g' },
    { tags: 'amoled' }
  ]
});

(2) $size matches the length of the array

JAVASCRIPT
// === Exact Match for Array Length ===
db.products.find({ tags: { $size: 3 } });
// The number of tags is exactly 3

// === Unsupported Ranges,Required $expr ===
db.products.find({
  $expr: { $gt: [{ $size: "$tags" }, 3] }
});
// Number of tags > 3

(3) $elemMatch Element Match (Key!)

JAVASCRIPT
// === Scene:Check the ratings in the reviews >= 4 and contains the keyword "good" Comments on ===
db.products.find({
  reviews: {
    $elemMatch: {
      rating: { $gte: 4 },
      content: /good/i
    }
  }
});
// ✅ Correct:A single comment meets both conditions at the same time

// === Counterexample:Do not use $elemMatch ===
db.products.find({
  "reviews.rating": { $gte: 4 },
  "reviews.content": /good/i
});
// ⚠️ Error:May match different comments(One comment, high rating,Another post containing the keyword)

▶ Example 4: Array Operators in Action

JAVASCRIPT
// === Scene:Student Course Registration System ===
db.students.insertMany([
  {
    name: "Alice",
    courses: [
      { name: "Math", score: 85 },
      { name: "Physics", score: 92 },
      { name: "Chemistry", score: 78 }
    ]
  },
  // ...
]);

// Search:Selected Math And the score >= 90 students
db.students.find({
  courses: {
    $elemMatch: { name: "Math", score: { $gte: 90 } }
  }
});

// Search:Selected 3 Students enrolled in courses at the undergraduate level or above
db.students.find({
  $expr: { $gte: [{ $size: "$courses" }, 3] }
});

// Search:All course grades are >= 80 students
db.students.find({
  courses: {
    $not: {
      $elemMatch: { score: { $lt: 80 } }
    }
  }
});

7. Evaluation Operators

Concept Explanation: Evaluation operators provide more flexible query capabilities—$regex supports regular expression matching (fuzzy search), $expr supports comparisons between fields using aggregate expressions, and $mod supports modulo operations. These operators are powerful but have poor performance and should be used as a "last resort"—index-friendly query methods should be prioritized.

How It Works: $regex By default, indexing is not supported (except for prefix-anchored queries ^pattern), so all documents must be scanned to perform regular expression matching. $expr When using aggregation pipeline expressions, the result of the expression is calculated for each document before comparison, which also results in poor performance. Neither of these should be used as the primary condition for high-frequency queries.

Operator Meaning Index-Friendly Performance Use Cases
$regex Regular expression matching ⚠️ Prefix-only matching Slow Fuzzy search
$expr Aggregate expression Very slow Comparison between fields
$mod Modulo Operation Slow Modulo Filtering

(1) $regex Regular Expression

JAVASCRIPT
// === Simple Regular Expressions ===
db.products.find({ title: /^iPhone/ });
// Title: "iPhone" Introduction

// === Case-insensitive ===
db.products.find({ title: { $regex: 'phone', $options: 'i' } });

// === Multimode Matching ===
db.products.find({
  title: { $regex: 'phone|mobile', $options: 'i' }
});

// === Performance Optimization:Regular Expression Anchoring(Avoid ^.* Wildcard)===
// ✅ Fast: db.products.find({ title: /^iPhone/ })
// ⚠️ Slow: db.products.find({ title: /iPhone/ })

(2) $expr uses an aggregate expression

JAVASCRIPT
// === Comparison Between Fields ===
db.products.find({
  $expr: { $gt: ["$discount", "$price"] }
});
// discount > price(Outlier Data)

// === Comparing Array Lengths ===
db.products.find({
  $expr: { $gte: [{ $size: "$tags" }, 5] }
});

// === String Operations ===
db.products.find({
  $expr: { $eq: [{ $substr: ["$title", 0, 5] }, "Hello"] }
});

(3) $mod: Modulo

JAVASCRIPT
// === Field-value pairs N Removing the Mold ===
db.products.find({ price: { $mod: [100, 0] } });
// The price can be 100 Divisibility by an Integer

// === Price Comparison 100 Removing the Mold = 50 ===
db.products.find({ price: { $mod: [100, 50] } });

8. Comprehensive Practical Training

Concept Explanation: In real-world business scenarios, queries rarely use a single operator—they are typically combinations of multiple operators. The key principles for combined queries are: place the most selective conditions first (to reduce the amount of data scanned by subsequent conditions), create indexes on the fields in all $or clauses, and avoid using complex aggregate expressions in $expr.

Principles of Performance Optimization:

  1. Equal value queries ($eq/$in) have the highest selectivity and should be placed first in the filter.
  2. Range queries ($gt/$lt) are the second most selective and should be placed after equality conditions.
  3. Each clause of $or should have independent index support
  4. $regex Indexes can only be used for prefix-based lookups; in all other cases, a full-table scan is performed.
  5. $expr Has the worst performance; use as a last resort
100%
graph TB
    A[Comprehensive Query Optimization] --> B[1. Equivalence Filtering<br/>Highest selectivity]
    A --> C[2. Range Filtering<br/>Selectivity is secondary]
    A --> D[3. Logic Combinations<br/>$and/$or]
    A --> E[4. Sort + Pagination<br/>sort + limit]
    
    B --> B1[{ category: 'E' }<br/>Index Scan]
    C --> C1[{ price: { $gte: 100 } }<br/>Range Scan]
    D --> D1[Combination of Multiple Conditions<br/>Merge Result Sets]
    E --> E1[Index Sorting<br/>Avoid Memory Sorting]

    style B1 fill:#d4edda
Optimization Strategy Query Method Index Requirements Performance
Optimal Equi-value + Index Sort Composite Index O(log N)
Good Equi-value + Range + Index Composite Index O(log N + K)
General $or + indexes of each clause Multiple independent indexes O(K * log N)
Poor $regex prefix anchoring prefix index O(log N + K)
Worst Case $expr / Unindexed Sort None O(N log N)

(1) Examples of Complex Queries

JAVASCRIPT
// === Scene:Advanced Search for E-commerce ===
// Price 100-1000、Electronics or Computers、Inventory > 0、
// Tags include 'bestseller' or 'new'、Rating >= 4、Have discount
db.products.find({
  $and: [
    { price: { $gte: 100, $lte: 1000 } },
    {
      $or: [
        { category: 'Electronics' },
        { category: 'Computers' }
      ]
    },
    { stock: { $gt: 0 } },
    { tags: { $in: ['bestseller', 'new'] } },
    { rating: { $gte: 4 } },
    { discount: { $exists: true, $ne: null } }
  ]
});

▶ Example 5: Operator Performance Comparison

JAVASCRIPT
// === Performance Testing:100 10,000 Documents ===

// ❌ Slow: Unindexed fields + $exists
db.users.find({ lastLoginAt: { $exists: true } });
// ~500ms(Full Table Scan)

// ✅ Fast: Index Field + Range Query
db.users.find({ age: { $gte: 18, $lt: 30 } });
// ~5ms(Index Scan)

// ❌ Slow: Regular expression not anchored
db.products.find({ title: /phone/i });
// ~300ms(Full Table Scan + Regular Expression Matching)

// ✅ Fast: Regular Expression Anchoring
db.products.find({ title: /^iPhone/ });
// ~10ms(Prefix Index)

❓ FAQ

Q What is the difference between $in and $or?
A $in is syntactic sugar and is equivalent to $or. { field: { $in: [A, B] } } is equivalent to { $or: [{ field: A }, { field: B }] }. They have the same performance, but $in is recommended because it is more concise.
Q What is the difference between $elemMatch and dot notation?
A { "a.b": 1, "a.c": 2 } may match different array elements for b and c; { a: { $elemMatch: { b: 1, c: 2 } } } requires that the same element satisfy both conditions simultaneously.
Q Why are regular expression queries slow?
A By default, regular expressions cannot use indexes (except for prefixes ^pattern). Non-anchored regular expressions require scanning all documents to perform the match, resulting in poor performance.
Q When should $expr be used?
A When you need to compare fields or use aggregate functions (such as $size, $substr, or $cond). However, $expr has poor performance, so use regular queries whenever possible.

📖 Summary


📝 Exercises

  1. Basic Question (⭐): Query Electronics products with prices between 100 and 500 and inventory greater than 0.
  2. Basic Question (⭐): Use $in to query products across multiple categories (Electronics/Books/Clothing).
  3. Advanced Problem (⭐⭐): Use $elemMatch to find products in the comments that have a "rating >= 4 and contain the keyword 'good'."
  4. Advanced Problem (⭐⭐): Use $expr to query products with more than 3 tags and a rating of 4 or higher.
  5. Challenge Question (⭐⭐⭐): Build complex queries (combinations of 5 or more operators), including AND/OR/NOT, $elemMatch, and $regex anchors, to test performance differences.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏