MongoDB Indexing and Search

Indexes let MongoDB find matching documents without scanning every document in a collection, turning slow queries into fast ones.

Why Indexes Matter

Without an index, MongoDB must perform a collection scan (COLLSCAN) — reading every document to find the ones that match a query filter. On a collection with a few dozen documents this is instant, but on a collection with millions of documents it becomes painfully slow. An index is a separate, ordered data structure (a B-tree) that stores the values of one or more fields along with a pointer back to the original document, so MongoDB can jump straight to the matching entries instead of scanning everything.

Every collection automatically gets one index for free: an index on the _id field. This is why looking up a document by _id is always fast, even on huge collections. Any other field you query frequently should usually get its own index.

Creating a Single-Field Index

The createIndex() method builds an index on one or more fields. Pass 1 for ascending order or -1 for descending order.

Create an index on the email field

db.users.createIndex({ email: 1 })

// Now this query uses the index instead of scanning
// the whole collection:
db.users.find({ email: "jo@example.com" })

Compound Indexes

A compound index covers multiple fields in a defined order. The order matters: MongoDB can use a compound index efficiently for queries that filter on a prefix of the indexed fields (the leftmost fields first), similar to how a phone book is sorted by last name, then first name.

Create a compound index

db.orders.createIndex({ customerId: 1, orderDate: -1 })

// Uses the index efficiently: filters on the prefix
// field (customerId) and sorts on the second field.
db.orders.find({ customerId: "cust_42" }).sort({ orderDate: -1 })

Checking Whether a Query Uses an Index

The explain() method reveals the query plan MongoDB chose. Look at the winningPlan stage: IXSCAN means an index was used, while COLLSCAN means MongoDB scanned the whole collection.

Inspect the query plan

db.orders.find({ customerId: "cust_42" }).explain("executionStats")

// executionStats.executionStages.stage will show
// "IXSCAN" when the compound index above is used.

Text Search Indexes

For searching free-form text (like blog posts or product descriptions), MongoDB offers a special text index. It tokenizes string fields into words, removes common stop words, and applies stemming, so a search for "running" also matches documents containing "run" or "runs".

Create and use a text index

db.articles.createIndex({ title: "text", body: "text" })

db.articles.find({ $text: { $search: "mongodb performance" } })
  • Single-field index — speeds up queries and sorts on one field.
  • Compound index — covers multiple fields; field order determines which query patterns benefit.
  • Text index — enables full-text search with stemming and stop-word removal.
  • Unique index — like a normal index but rejects duplicate values.
  • TTL index — automatically deletes documents after a set time, useful for session or log data.
Index TypeBest ForExample
Single fieldEquality or range lookups on one field{ email: 1 }
CompoundQueries filtering/sorting on several fields{ status: 1, createdAt: -1 }
TextFree-text search across string fields{ title: "text" }
UniqueEnforcing no duplicate values{ username: 1 } unique
Note: Every index speeds up reads but slows down writes slightly, since MongoDB must update every index whenever a document changes. Only index fields you actually query, sort, or search on.
Note: A text index only works well if $text is part of the query. Regular find() filters on the same field, without $text, will still fall back to a collection scan.

Exercise: MongoDB Indexing and Search

What is the main purpose of adding an index to a collection?