Mongo Reference Guideline

MongoDB queries are used to interact with the data stored in MongoDB collections. This guide covers CRUD operations, query operators, aggregation, indexes, and more.

Table of contents

  1. 1. Basic Query Syntax
    1. Example:
  2. 2. CRUD Operations
    1. Create
    2. Read
    3. Update
    4. Delete
  3. 3. Query Operators
    1. Comparison Operators
    2. Logical Operators
    3. Element Operators
  4. 4. Projection
  5. 5. Sorting, Limiting, Skipping
  6. 6. Basic Aggregation Framework
    1. Common Aggregation Stages:
  7. 7. Array Queries
    1. Match array elements:
    2. Match specific array conditions:
  8. 8. Regular Expressions
  9. 9. Basic Text Search
    1. How It Works:
    2. What this Does:
    3. MongoDB Built-in Text Search Overview
    4. Limitations (Compared to Atlas Search)
  10. 10. Indexing
    1. Create Index:
    2. Compound Index:
    3. View Indexes:
  11. 11. Data Types (BSON Types)
  12. 12. Miscellaneous
    1. Count Documents:
    2. Distinct Values:
    3. Rename a Field:
  13. 13. Tips & Best Practices
  14. 14. Sample Collection: users
    1. Mongo Play Ground and Search Play Ground
    2. Basic Find
    3. Comparison
    4. Boolean Fields
    5. Embedded Documents
    6. Arrays
    7. Projections
    8. Sorting & Limiting
    9. Dates
    10. Regex & Text
    11. Logical Operators
    12. Aggregation Examples
    13. Updates
    14. Deletes
    15. Count, Distinct, Exists
  15. 15. Aggregation Framework
    1. Basic Syntax
    2. Common Aggregation Stages
    3. Expressions (Used in $project, $addFields, etc.)
    4. Example Aggregation Pipeline
    5. Performance Tips
    6. Summary Table of Key Stages
  16. 16. Detailed Aggregation Stages
    1. $lookup – Aggregation Joins
    2. $facet - multiple sub-pipelines in parallel on the same set of input documents.
    3. $bucket - Groups documents into buckets (bins)
  17. 17. Atlas Search Index
    1. Search Index
    2. How to Create a Search Index
    3. Basic $search Syntax
    4. Common $search Operators
    5. Score Boosting and Control
    6. Example: Boost title matches higher
    7. Search with Aggregation
    8. Facets and Highlighting
    9. Search Index Definition Features
    10. Summary of Operators
    11. Demo Setup
  18. 18. MongoDB vs Relational Database - Complete Comparison
    1. Key Decision Factors

1. Basic Query Syntax

db.collection.find(query, projection)
  • query: Filters the documents.
  • projection: Optional. Specifies fields to return.

Example:

db.users.find({ age: { $gte: 18 } }, { name: 1, age: 1 })

2. CRUD Operations

Create

db.collection.insertOne(document)
db.collection.insertMany([document1, document2, ...])

Read

db.collection.find(query, projection)
db.collection.findOne(query)

Update

db.collection.updateOne(filter, update)
db.collection.updateMany(filter, update)
db.collection.replaceOne(filter, replacement)
  • Update operators: $set, $inc, $push, $addToSet, $unset

Delete

db.collection.deleteOne(filter)
db.collection.deleteMany(filter)

3. Query Operators

Comparison Operators

OperatorDescription
$eqEquals
$neNot equal
$gtGreater than
$gteGreater or equal
$ltLess than
$lteLess or equal
$inIn array
$ninNot in array
db.products.find({ price: { $gte: 50, $lte: 100 } })

Logical Operators

OperatorDescription
$andLogical AND
$orLogical OR
$notLogical NOT
$norNOR
db.users.find({
  $or: [{ age: { $lt: 18 } }, { isActive: true }]
})

Element Operators

OperatorDescription
$existsField exists or not
$typeField is of a type
db.users.find({ phone: { $exists: true } })

4. Projection

Specify fields to include (1) or exclude (0):

db.users.find({}, { name: 1, _id: 0 })

5. Sorting, Limiting, Skipping

db.collection.find().sort({ field: 1 })  // 1 = ASC, -1 = DESC
db.collection.find().limit(n)
db.collection.find().skip(n)

6. Basic Aggregation Framework

Used for advanced data processing:

db.collection.aggregate([
  { $match: { status: "active" } },
  { $group: { _id: "$category", total: { $sum: "$amount" } } },
  { $sort: { total: -1 } }
])

Common Aggregation Stages:

StageDescription
$matchFilter data
$groupGroup and aggregate
$projectShape the output
$sortSort results
$limitLimit the number of results
$skipSkip documents
$unwindDeconstruct arrays
$lookupJoin with another collection

7. Array Queries

Match array elements:

db.orders.find({ items: "apple" })

Match specific array conditions:

db.orders.find({ qty: { $all: [5, 10] } })
db.orders.find({ qty: { $elemMatch: { $gt: 5, $lt: 20 } } })

8. Regular Expressions

db.users.find({ name: /john/i })  // Case-insensitive match

  1. Sample Document
     {
       _id: ObjectId("..."),
       name: "Samsung Galaxy S21 Ultra",
       description: "Flagship smartphone with 108MP camera and 5000mAh battery",
       category: "Smartphones",
       brand: "Samsung"
     }
    
  2. Create a text index:

     db.products.createIndex({
       name: "text",
       description: "text",
       brand: "text"
     })
    
  3. Perform a text search:

    Basic Search

     db.products.find({
       $text: { $search: "samsung galaxy" }
     })
    

    Phrase Search

     db.products.find({
       $text: { $search: "\"Galaxy S21 Ultra\"" }
     })
    

    Exclude Terms

     db.products.find({
       $text: { $search: "galaxy -case" }
     })
    

    Ranked by Relevance

     db.products.find(
       { $text: { $search: "flagship smartphone" } },
       { score: { $meta: "textScore" } }
     ).sort({ score: { $meta: "textScore" } })
    

How It Works:

MongoDB builds an internal searchable word map from these fields.

This index supports efficient keyword and phrase matching.

What this Does:

Finds documents where the title or content contains “MongoDB”, “indexing”, or both.

Uses natural language processing (NLP) like stemming and stop word filtering.

Feature$text (Basic Text Search)Atlas Search ($search)
Supports custom paths?❌ No✅ Yes
Supports nested fields?❌ No✅ Yes
Flexible indexing?❌ One text index only✅ Fully configurable
Use caseSimple keyword searchAdvanced full-text search

MongoDB Built-in Text Search Overview

Supported:

  • Searching strings in one or more fields
  • Phrase search
  • Logical operators (AND, OR, NOT)
  • Relevance scoring (textScore)

Not Supported:

  • Autocomplete
  • Fuzzy search (typos)
  • Nested fields or advanced analyzers
FeatureText IndexAtlas Search
TokenizationBasicAdvanced
Fuzzy Match
Autocomplete
Synonyms
Score BoostingLimitedAdvanced
Nested Field Search
Language SupportBasicExtensive

10. Indexing

Create Index:

db.collection.createIndex({ field: 1 })

Compound Index:

db.collection.createIndex({ field1: 1, field2: -1 })

View Indexes:

db.collection.getIndexes()

11. Data Types (BSON Types)

TypeNumber
Double1
String2
Object3
Array4
Binary Data5
ObjectId7
Boolean8
Date9
Null10
Regex11

Example:

db.collection.find({ field: { $type: "string" } })

12. Miscellaneous

Count Documents:

db.collection.countDocuments({ field: value })

Distinct Values:

db.collection.distinct("field", { query })

Rename a Field:

db.collection.updateMany({}, { $rename: { "oldField": "newField" } })

13. Tips & Best Practices

  • Always index fields used in queries or $lookup.
  • Avoid unbounded $regex on unindexed fields.
  • Use explain() to analyze query performance.
  • Use projection to reduce payload size.
  • Normalize or embed documents depending on access pattern.

14. Sample Collection: users

[
  {
    "_id": "1",
    "name": "Alice",
    "age": 28,
    "email": "alice@example.com",
    "isActive": true,
    "address": {
      "city": "New York",
      "zip": "10001"
    },
    "roles": ["admin", "editor"],
    "lastLogin": ISODate("2025-05-20T10:00:00Z")
  },
  {
    "_id": "2",
    "name": "Bob",
    "age": 35,
    "email": "bob@example.com",
    "isActive": false,
    "address": {
      "city": "Chicago",
      "zip": "60601"
    },
    "roles": ["viewer"],
    "lastLogin": ISODate("2025-05-25T14:30:00Z")
  },
  {
    "_id": "3",
    "name": "Carol",
    "age": 22,
    "email": "carol@example.com",
    "isActive": true,
    "address": {
      "city": "Los Angeles",
      "zip": "90001"
    },
    "roles": ["editor"],
    "lastLogin": ISODate("2025-05-28T08:00:00Z")
  }
]

Mongo Play Ground and Search Play Ground


Basic Find

db.users.find()  // All documents
db.users.find({ name: "Alice" })  // Filter by exact match

Comparison

db.users.find({ age: { $gt: 25 } })
db.users.find({ age: { $gte: 28, $lte: 35 } })
db.users.find({ age: { $ne: 22 } })

Boolean Fields

db.users.find({ isActive: true })

Embedded Documents

db.users.find({ "address.city": "Chicago" })
db.users.find({ "address.zip": { $in: ["10001", "60601"] } })

Arrays

db.users.find({ roles: "admin" })  // Element match
db.users.find({ roles: { $all: ["admin", "editor"] } })
db.users.find({ roles: { $size: 2 } })

Projections

db.users.find({}, { name: 1, email: 1, _id: 0 })

Sorting & Limiting

db.users.find().sort({ age: -1 }).limit(2)

Dates

db.users.find({ lastLogin: { $gt: ISODate("2025-05-21T00:00:00Z") } })

Regex & Text

db.users.find({ name: /a/i })  // Case-insensitive match

Optional: Create a text index and use full-text search

db.users.createIndex({ name: "text", email: "text" })
db.users.find({ $text: { $search: "Alice" } })

Logical Operators

db.users.find({
  $and: [{ isActive: true }, { age: { $gt: 25 } }]
})

db.users.find({
  $or: [{ "address.city": "Chicago" }, { "address.city": "Los Angeles" }]
})

db.users.find({
  age: { $not: { $gt: 30 } }
})

Aggregation Examples

// Count users by city
db.users.aggregate([
  { $group: { _id: "$address.city", count: { $sum: 1 } } }
])

// Average age of active users
db.users.aggregate([
  { $match: { isActive: true } },
  { $group: { _id: null, avgAge: { $avg: "$age" } } }
])

Updates

db.users.updateOne(
  { name: "Bob" },
  { $set: { isActive: true } }
)

db.users.updateMany(
  { isActive: false },
  { $set: { lastLogin: new Date() } }
)

db.users.updateOne(
  { name: "Alice" },
  { $push: { roles: "superadmin" } }
)

Deletes

db.users.deleteOne({ name: "Carol" })
db.users.deleteMany({ age: { $lt: 25 } })

Count, Distinct, Exists

db.users.countDocuments({ isActive: true })
db.users.distinct("address.city")
db.users.find({ "phone": { $exists: false } })

15. Aggregation Framework

The aggregation framework processes data records and returns computed results. It’s like SQL’s GROUP BY, JOIN, and SELECT functions — but more powerful and pipeline-based.


Basic Syntax

db.collection.aggregate([
  { stage1 },
  { stage2 },
  ...
])

Each stage transforms the documents in some way.


Common Aggregation Stages

1. $match: Filter documents

{ $match: { status: "active" } }

Like WHERE in SQL.


2. $group: Group and aggregate

{
  $group: {
    _id: "$category",
    total: { $sum: "$price" },
    avgPrice: { $avg: "$price" }
  }
}

Like GROUP BY.


3. $project: Shape documents

{
  $project: {
    name: 1,
    priceWithTax: { $multiply: ["$price", 1.1] }
  }
}

Transforms or renames fields.


4. $sort: Sort documents

{ $sort: { price: -1 } } // Descending

5. $limit and $skip: Pagination

{ $skip: 10 },
{ $limit: 5 }

6. $lookup: Join another collection

{
  $lookup: {
    from: "orders",
    localField: "_id",
    foreignField: "userId",
    as: "orders"
  }
}

7. $unwind: Flatten arrays

{ $unwind: "$tags" }

8. $facet: Multiple parallel pipelines

A facet is a stage in the aggregation pipeline ($facet) that allows you to run multiple sub-pipelines in parallel on the same set of input documents — and then return all their results together in a single document.

{
  $facet: {
    countByCategory: [
      { $group: { _id: "$category", count: { $sum: 1 } } }
    ],
    recentItems: [
      { $sort: { createdAt: -1 } },
      { $limit: 5 }
    ]
  }
}

9. $addFields: Add computed fields

{ $addFields: { total: { $add: ["$price", "$tax"] } } }

10. $set: Alias for $addFields

{ $set: { isActive: true } }

11. $count: Count documents

{ $count: "total" }

12. $bucket & $bucketAuto: Group by ranges

{
  $bucket: {
    groupBy: "$price",
    boundaries: [0, 100, 500, 1000],
    default: "Other",
    output: { count: { $sum: 1 } }
  }
}

Expressions (Used in $project, $addFields, etc.)

  • $add, $subtract, $multiply, $divide
  • $concat, $toUpper, $toLower, $substr
  • $year, $month, $dayOfWeek, $dateToString
  • $cond, $ifNull, $switch

Example Aggregation Pipeline

Goal: Get average order amount per user with order count

db.orders.aggregate([
  {
    $group: {
      _id: "$userId",
      totalSpent: { $sum: "$amount" },
      avgSpent: { $avg: "$amount" },
      orderCount: { $sum: 1 }
    }
  },
  {
    $sort: { totalSpent: -1 }
  }
])

Performance Tips

  • Use $match and $project early to reduce data volume.
  • Always index fields used in $match, especially before $lookup.
  • Use $merge to write results to a new collection.
  • Use $out or $merge for reporting workflows.

Summary Table of Key Stages

StageUse Case
$matchFilter input
$groupAggregate by key
$projectShape output
$sortSort result
$limitLimit documents
$skipSkip N documents
$lookupJoin with another collection
$unwindFlatten arrays
$facetMultiple result sets in one pass
$countCount documents
$bucketBin documents by range

16. Detailed Aggregation Stages

$lookup – Aggregation Joins

Purpose

$lookup allows you to join documents from another collection into your aggregation pipeline.

Sample Collections

Collection: users

[
  {
    "_id": 1,
    "name": "Alice",
    "age": 28
  },
  {
    "_id": 2,
    "name": "Bob",
    "age": 35
  }
]

Collection: orders

[
  {
    "_id": 101,
    "userId": 1,
    "item": "Laptop",
    "amount": 1200
  },
  {
    "_id": 102,
    "userId": 1,
    "item": "Mouse",
    "amount": 25
  },
  {
    "_id": 103,
    "userId": 2,
    "item": "Monitor",
    "amount": 300
  }
]

Basic $lookup

db.users.aggregate([
  {
    $lookup: {
      from: "orders",          // foreign collection
      localField: "_id",       // field in users
      foreignField: "userId",  // field in orders
      as: "userOrders"         // output array field
    }
  }
])

Output:

[
  {
    "_id": 1,
    "name": "Alice",
    "age": 28,
    "userOrders": [
      { "_id": 101, "userId": 1, "item": "Laptop", "amount": 1200 },
      { "_id": 102, "userId": 1, "item": "Mouse", "amount": 25 }
    ]
  },
  {
    "_id": 2,
    "name": "Bob",
    "age": 35,
    "userOrders": [
      { "_id": 103, "userId": 2, "item": "Monitor", "amount": 300 }
    ]
  }
]

$lookup + $unwind

To flatten the joined array into individual documents:

db.users.aggregate([
  {
    $lookup: {
      from: "orders",
      localField: "_id",
      foreignField: "userId",
      as: "userOrders"
    }
  },
  { $unwind: "$userOrders" }
])

$lookup with $group

To calculate total spend per user:

db.users.aggregate([
  {
    $lookup: {
      from: "orders",
      localField: "_id",
      foreignField: "userId",
      as: "orders"
    }
  },
  {
    $project: {
      name: 1,
      totalSpent: { $sum: "$orders.amount" }
    }
  }
])

Advanced $lookup (Pipeline Form) – MongoDB 3.6+

Allows filtering or projecting within the join.

db.users.aggregate([
  {
    $lookup: {
      from: "orders",
      let: { userId: "$_id" },
      pipeline: [
        { $match: { $expr: { $eq: ["$userId", "$$userId"] } } },
        { $match: { amount: { $gt: 100 } } },
        { $project: { item: 1, amount: 1, _id: 0 } }
      ],
      as: "bigOrders"
    }
  }
])

$lookup Best Practices

  • Index foreignField in the joined collection for performance.
  • Avoid joining large collections in real-time user queries.
  • Use $unwind and $project for formatting the output cleanly.

$lookup Summary

FeatureSQL Equivalent
$lookupJOIN
localField + foreignFieldON clause
$unwindRow expansion
$group, $projectGROUP BY, SELECT

$facet - multiple sub-pipelines in parallel on the same set of input documents.

$facet runs multiple sub-pipelines in parallel on the same input documents and outputs their results together. It’s incredibly useful for multi-dimensional analysis, such as paginated results + counts, or filtering + faceted navigation (like on e-commerce sites).

Syntax

db.collection.aggregate([
  {
    $facet: {
      output1: [ pipeline1 ],
      output2: [ pipeline2 ],
      ...
    }
  }
])

Each field (e.g., output1) defines a sub-pipeline that processes the same documents independently.

Example: products Collection

[
  { _id: 1, name: "Phone", category: "Electronics", price: 499 },
  { _id: 2, name: "Laptop", category: "Electronics", price: 1299 },
  { _id: 3, name: "Shoes", category: "Clothing", price: 79 },
  { _id: 4, name: "Watch", category: "Accessories", price: 199 },
  { _id: 5, name: "Headphones", category: "Electronics", price: 199 }
]

Sample $facet Query

Goal: Get a count by category, and a list of items priced under $500.

db.products.aggregate([
  {
    $facet: {
      "categoryCounts": [
        {
          $group: {
            _id: "$category",
            names: {
              $push: "$name"
            },
            count: {
              $sum: 1
            }
          }
        },
        {
          $project: {
            _id: 0,
            category: "$_id",
            names: 1,
            count: 1
          }
        }
      ],
      "under500": [
        {
          $match: {
            price: {
              $lt: 500
            }
          }
        },
        {
          $project: {
            name: 1,
            price: 1,
            _id: 1
          }
        }
      ]
    }
  }
])

Output:

[
  {
    "categoryCounts": [
      {
        "category": "Clothing",
        "count": 1,
        "names": [
          "Shoes"
        ]
      },
      {
        "category": "Accessories",
        "count": 1,
        "names": [
          "Watch"
        ]
      },
      {
        "category": "Electronics",
        "count": 3,
        "names": [
          "Phone",
          "Laptop",
          "Headphones"
        ]
      }
    ],
    "under500": [
      {
        "_id": 1,
        "name": "Phone",
        "price": 499
      },
      {
        "_id": 3,
        "name": "Shoes",
        "price": 79
      },
      {
        "_id": 4,
        "name": "Watch",
        "price": 199
      },
      {
        "_id": 5,
        "name": "Headphones",
        "price": 199
      }
    ]
  }
]

$facet Use Cases

Use CaseExample
Faceted navigationE-commerce filters (e.g., size, brand, color)
Pagination + total countPage of results + total available documents
Multi-metric reportingAvg price, count by category, top-selling items
Complex dashboardsMultiple charts/tables from one aggregation run

Nested Facets

You can even nest $facet within a facet sub-pipeline, though it’s advanced and should be used cautiously for performance reasons.

$facet Best Practices

  • Use projections early in pipelines to reduce document size.
  • Avoid too many sub-pipelines if performance is a concern.
  • Use $match outside the $facet to pre-filter if possible.

$bucket - Groups documents into buckets (bins)

Purpose:

The $bucket stage groups documents into buckets (bins) based on a field’s value. It’s used to create histogram-like groupings, such as price ranges or age brackets.

Example Input Collection: products

[
  { "name": "Pencil", "price": 1 },
  { "name": "Notebook", "price": 50 },
  { "name": "Keyboard", "price": 150 },
  { "name": "Monitor", "price": 300 },
  { "name": "Laptop", "price": 800 },
  { "name": "Phone", "price": 999 },
  { "name": "TV", "price": 1100 }
]

Aggregation Query:

db.products.aggregate([
  {
    $bucket: {
      groupBy: "$price",                      // Field to group by
      boundaries: [0, 100, 500, 1000],        // Bucket ranges (inclusive lower, exclusive upper)
      default: "Other",                       // Bucket for out-of-range values
      output: {
        count: { $sum: 1 },                   // Count per bucket
        items: { $push: "$name" }             // Optional: List item names
      }
    }
  }
])

How Buckets Are Built:

Bucket RangeMatches
0 ≤ price < 100Pencil, Notebook
100 ≤ price < 500Keyboard, Monitor
500 ≤ price < 1000Laptop, Phone
Other (≥1000 or <0)TV

Output:

[
  {
    "_id": 0,
    "count": 2,
    "items": ["Pencil", "Notebook"]
  },
  {
    "_id": 100,
    "count": 2,
    "items": ["Keyboard", "Monitor"]
  },
  {
    "_id": 500,
    "count": 2,
    "items": ["Laptop", "Phone"]
  },
  {
    "_id": "Other",
    "count": 1,
    "items": ["TV"]
  }
]

17. Atlas Search Index

MongoDB Atlas Search enables full-text search capabilities within your database using Lucene-powered search indexes. It integrates seamlessly with the aggregation framework using the $search stage.

See: search-playground

Search Index

  • A Search Index is a Lucene-style index defined at the collection level.
  • Enables fast, advanced search features (e.g., text relevance, autocomplete, faceted search).
  • Accessed using the $search stage in an aggregation pipeline.

How to Create a Search Index

Using Atlas UI:

  1. Go to your cluster in MongoDB Atlas.
  2. Click Search tab.
  3. Choose Create Search Index.
  4. Select Fields to index or use the Dynamic Mapping.

Example: JSON Index Definition

{
  "mappings": {
    "dynamic": false,
    "fields": {
      "title": { "type": "string" },
      "description": { "type": "string" },
      "price": { "type": "number" },
      "tags": { "type": "string" }
    }
  }
}

Basic $search Syntax

db.products.aggregate([
  {
    $search: {
      index: "default",  // Optional if using default index
      text: {
        query: "laptop",
        path: ["title", "description"]
      }
    }
  }
])

Common $search Operators

OperatorDescription
textFull-text search
autocompletePartial word matching
compoundCombine multiple search clauses (AND/OR/NOT)
phraseMatch exact phrases
wildcardPattern-based matching (e.g., lap*)
regexRegular expression matching
rangeNumeric/date range search
embeddedDocumentSearch inside subdocuments
existsMatch documents that contain a field

Score Boosting and Control

  • $meta: "searchScore" gives relevance score.
  • Use score inside operators to boost relevance.

Example: Boost title matches higher

text: {
  query: "laptop",
  path: ["title", "description"],
  score: {
    boost: {
      value: 3,
      path: { value: "title" }
    }
  }
}

Search with Aggregation

Combine $search with aggregation stages like $match, $project, $facet, $limit.

db.products.aggregate([
  {
    $search: {
      text: {
        query: "smartphone",
        path: ["title"]
      }
    }
  },
  { $match: { price: { $lt: 1000 } } },
  { $project: { title: 1, price: 1, score: { $meta: "searchScore" } } },
  { $sort: { score: -1 } },
  { $limit: 5 }
])

Facets and Highlighting

$searchMeta with facet

db.products.aggregate([
  {
    $searchMeta: {
      facet: {
        operator: {
          text: { query: "laptop", path: "title" }
        },
        facets: {
          categoryFacet: {
            type: "string",
            path: "category"
          },
          priceRanges: {
            type: "number",
            path: "price",
            boundaries: [0, 500, 1000],
            default: "Other"
          }
        }
      }
    }
  }
])

Highlighting (in $search only)

$search: {
  text: {
    query: "watch",
    path: "description"
  },
  highlight: {
    path: "description"
  }
}

Then use:

{ $project: { description: 1, highlights: { $meta: "searchHighlights" } } }

Search Index Definition Features

FeatureTypeDescription
stringtextFull-text, fuzzy, exact matching
numbernumericRange search (price, rating)
datedateSupports ISODate filtering
booleanbooleanTrue/false filtering
arraymixedIndexed array contents
dynamic: truewildcardAuto-index all fields
analyzersadvancedCustom tokenization and stemming

Summary of Operators

OperatorUse Case
textFull-text match
autocompleteSuggest-as-you-type
phraseExact match for phrases
rangePrice/date filters
compoundCombine multiple logic branches
facetCount by field or range
highlightHighlight match snippets

Demo Setup

Create a collection

Database: shop Collection: products

Run this in MongoDB Shell, Compass, or Atlas UI:

use shop;

db.products.insertMany([
  {
    name: "Laptop",
    description: "Powerful and portable computing device",
    translations: {
      en: {
        name: "Laptop",
        description: "Powerful and portable computing device"
      },
      es: {
        name: "Portátil",
        description: "Dispositivo informático potente y portátil"
      },
      fr: {
        name: "Ordinateur portable",
        description: "Appareil informatique puissant et portable"
      },
      de: {
        name: "Laptop",
        description: "Leistungsstarkes und tragbares Computergerät"
      }
    },
    category: "Electronics",
    price: 1200,
    defaultLanguage: "en"
  },
  {
    name: "Phone",
    description: "Fast, sleek smartphone",
    translations: {
      en: {
        name: "Phone",
        description: "Fast, sleek smartphone"
      },
      es: {
        name: "Teléfono",
        description: "Teléfono inteligente rápido y elegante"
      },
      fr: {
        name: "Téléphone",
        description: "Smartphone rapide et élégant"
      },
      de: {
        name: "Telefon",
        description: "Schnelles, elegantes Smartphone"
      }
    },
    category: "Electronics",
    price: 499,
    defaultLanguage: "en"
  },
  {
    name: "Shoes",
    description: "Comfortable running shoes",
    translations: {
      en: {
        name: "Shoes",
        description: "Comfortable running shoes"
      },
      es: {
        name: "Zapatos",
        description: "Zapatos cómodos para correr"
      },
      fr: {
        name: "Chaussures",
        description: "Chaussures de course confortables"
      },
      de: {
        name: "Schuhe",
        description: "Bequeme Laufschuhe"
      }
    },
    category: "Clothing",
    price: 79,
    defaultLanguage: "en"
  },
  {
    name: "Watch",
    description: "Stylish analog watch",
    translations: {
      en: {
        name: "Watch",
        description: "Stylish analog watch"
      },
      es: {
        name: "Reloj",
        description: "Reloj analógico elegante"
      },
      fr: {
        name: "Montre",
        description: "Montre analogique élégante"
      },
      de: {
        name: "Uhr",
        description: "Stilvolle analoge Uhr"
      }
    },
    category: "Accessories",
    price: 199,
    defaultLanguage: "en"
  },
  {
    name: "Headphones",
    description: "Noise-cancelling headphones",
    translations: {
      en: {
        name: "Headphones",
        description: "Noise-cancelling headphones"
      },
      es: {
        name: "Auriculares",
        description: "Auriculares con cancelación de ruido"
      },
      fr: {
        name: "Écouteurs",
        description: "Écouteurs à réduction de bruit"
      },
      de: {
        name: "Kopfhörer",
        description: "Geräuschunterdrückende Kopfhörer"
      }
    },
    category: "Electronics",
    price: 199,
    defaultLanguage: "en"
  }
]);

Create a Search Index

If you’re using MongoDB Atlas, go to:

Cluster > Collections > shop.products > Search > Create Index

Choose JSON Editor and paste:

{
  "mappings": {
    "dynamic": false,
    "fields": {
      "name": {
        "type": "autocomplete",
        "analyzer": "lucene.english",
        "foldDiacritics": true,
        "maxGrams": 12,
        "minGrams": 3,
        "tokenization": "edgeGram"
      },
      "description": {
        "type": "string",
        "analyzer": "lucene.english"
      },
      "category": {
        "type": "string"
      },
      "price": {
        "type": "number"
      },
      "translations": {
        "type": "document",
        "fields": {
          "en": {
            "type": "document",
            "fields": {
              "name": {
                "type": "autocomplete",
                "analyzer": "lucene.english",
                "foldDiacritics": true,
                "maxGrams": 12,
                "minGrams": 3,
                "tokenization": "edgeGram"
              },
              "description": {
                "type": "string",
                "analyzer": "lucene.english"
              }
            }
          },
          "es": {
            "type": "document",
            "fields": {
              "name": {
                "type": "autocomplete",
                "analyzer": "lucene.spanish",
                "foldDiacritics": true,
                "maxGrams": 12,
                "minGrams": 3,
                "tokenization": "edgeGram"
              },
              "description": {
                "type": "string",
                "analyzer": "lucene.spanish"
              }
            }
          },
          "fr": {
            "type": "document",
            "fields": {
              "name": {
                "type": "autocomplete",
                "analyzer": "lucene.french",
                "foldDiacritics": true,
                "maxGrams": 12,
                "minGrams": 3,
                "tokenization": "edgeGram"
              },
              "description": {
                "type": "string",
                "analyzer": "lucene.french"
              }
            }
          },
          "de": {
            "type": "document",
            "fields": {
              "name": {
                "type": "autocomplete",
                "analyzer": "lucene.german",
                "foldDiacritics": true,
                "maxGrams": 12,
                "minGrams": 3,
                "tokenization": "edgeGram"
              },
              "description": {
                "type": "string",
                "analyzer": "lucene.german"
              }
            }
          }
        }
      }
    }
  }
}

Or enable dynamic: true to auto-index everything for now.

Search Query Set

1. Basic Full-Text Search

db.products.aggregate([
  {
    $search: {
      text: {
        query: "smartphone",
        path: ["name", "description"]
      }
    }
  }
])

2. Search + Price Filter

db.products.aggregate([
  {
    $search: {
      text: {
        query: "watch",
        path: ["name", "description"]
      }
    }
  },
  {
    $match: { price: { $lt: 500 } }
  }
])

3. Highlighting Matches

db.products.aggregate([
  {
    $search: {
      text: {
        query: "noise",
        path: "description"
      },
      highlight: { path: "description" }
    }
  },
  {
    $project: {
      name: 1,
      description: 1,
      highlights: { $meta: "searchHighlights" }
    }
  }
])

4. Faceted Search with $searchMeta

db.products.aggregate([
  {
    $searchMeta: {
      facet: {
        operator: {
          text: {
            query: "headphones",
            path: "description"
          }
        },
        facets: {
          categoryFacet: {
            type: "string",
            path: "category"
          },
          priceRanges: {
            type: "number",
            path: "price",
            boundaries: [0, 100, 500, 1000],
            default: "Other"
          }
        }
      }
    }
  }
])

5. Autocomplete (needs special index)

db.products.aggregate([
  {
    $search: {
      index: "autocomplete_index",
      autocomplete: {
        query: "lap",
        path: "name", // Simple root-level search
        fuzzy: { maxEdits: 2 }
      }
    }
  }
])
db.products.aggregate([
  {
    $search: {
      index: "autocomplete_index",
      autocomplete: {
        query: "por",
        path: "translations.es.name",
        fuzzy: { maxEdits: 2 }
      }
    }
  }
])

Ready to Use

You can test all these queries directly in:

  • MongoDB Atlas > Aggregation Builder
  • MongoDB Compass > Aggregation Tab
  • mongosh or MongoDB Shell

18. MongoDB vs Relational Database - Complete Comparison

ConceptRelational DatabaseMongoDBDescription/Analogy
DatabaseDatabaseDatabaseBoth: Container for all data - like a library building
SchemaFixed Schema (DDL)Flexible SchemaRelational: Strict blueprint that must be followed
MongoDB: Flexible guidelines that can evolve
Data StructureTablesCollectionsRelational: Organized shelves with identical slots
MongoDB: Themed sections with varied content
Data RecordsRows/RecordsDocumentsRelational: Standardized catalog cards
MongoDB: Flexible information packets (JSON-like)
Data FieldsColumnsFieldsRelational: Pre-defined categories
MongoDB: Customizable attributes
Primary KeyPrimary Key_id (ObjectId)Both: Unique identifier for each record
RelationshipsForeign Keys + JOINsEmbedded Docs or ReferencesRelational: Separate linked tables
MongoDB: Nested data or manual references
Data TypesStrict SQL Data TypesBSON Data TypesRelational: varchar, int, date, etc.
MongoDB: string, number, array, object, etc.
QueriesSQLMQL (MongoDB Query Language)Relational: SELECT, FROM, WHERE
MongoDB: find(), aggregate(), match()
TransactionsACID TransactionsMulti-Document TransactionsBoth support, but different implementation approaches
IndexingB-Tree IndexesVarious Index TypesRelational: Standard B-tree
MongoDB: Compound, text, geospatial, etc.
ScalingVertical Scaling (Scale Up)Horizontal Scaling (Scale Out)Relational: Bigger, more powerful servers
MongoDB: More servers in cluster
ClusteringMaster-Slave ReplicationReplica SetsRelational: Primary-secondary setup
MongoDB: Automatic failover groups
ShardingManual/ComplexBuilt-in ShardingRelational: Difficult to partition
MongoDB: Automatic data distribution
ConsistencyStrong ConsistencyEventual Consistency (configurable)Relational: Immediate consistency
MongoDB: Tunable consistency levels
Storage EngineVarious (InnoDB, MyISAM)WiredTiger, MMAPv1Different underlying storage mechanisms
JoinsNative SQL JOINs$lookup (aggregation)Relational: Efficient cross-table queries
MongoDB: Aggregation pipeline joins
NormalizationNormalized (1NF, 2NF, 3NF)DenormalizedRelational: Data split across tables
MongoDB: Data often stored together
AggregationGROUP BY, HAVINGAggregation PipelineRelational: SQL aggregation functions
MongoDB: Multi-stage data processing
ViewsDatabase ViewsViewsBoth: Virtual tables/collections based on queries
Stored ProceduresStored Procedures/FunctionsServer-side JavaScriptRelational: SQL-based procedures
MongoDB: JavaScript functions
TriggersDatabase TriggersChange StreamsRelational: Automatic actions on data changes
MongoDB: Real-time change notifications
BackupSQL Dumps, Binary Logsmongodump, Filesystem SnapshotsDifferent backup and recovery strategies
AdministrationDatabase Administrator (DBA)Database AdministratorBoth require administration, different skill sets
Data ModelingEntity-Relationship (ER)Document-OrientedRelational: Tables with relationships
MongoDB: Nested document structures
Use CasesOLTP, Complex Queries, ReportsContent Management, Real-time AnalyticsRelational: Financial systems, ERP
MongoDB: Social media, IoT, catalogs
ExamplesMySQL, PostgreSQL, Oracle, SQL ServerMongoDB, Amazon DocumentDBPopular implementations of each approach

Key Decision Factors

Choose Relational DB when:

  • Complex relationships between data
  • Need ACID transactions
  • Well-defined, stable schema
  • Complex reporting and analytics
  • Strong consistency requirements

Choose MongoDB when:

  • Rapidly evolving data structures
  • Need horizontal scaling
  • Working with semi-structured data
  • Agile development environment
  • Geographic distribution requirements