Create Indexes to Speed Up Queries

Learn how to create indexes in MongoDB to dramatically speed up your queries. This lesson covers basic index creation, choosing the right fields, and troubleshooting common pitfalls.

Focus: create indexes to speed up queries

Sponsored

Your MongoDB queries are getting slower and slower as your collections grow. You've tried adding more RAM, upgrading your machine, and even rewriting your queries — but nothing seems to help. The real culprit is often a missing index: MongoDB is scanning every document in your collection just to find a few matching records. In this lesson, you'll learn how to create indexes to speed up queries, turning those painful full collection scans into lightning-fast index lookups. By the end, you'll be able to identify slow queries, create the right indexes, and understand when (and when not) to index.

The problem this lesson solves

Imagine you run an e-commerce site with a products collection. Your users often search for products by category and price range:

db.products.find({ category: "electronics", price: { $lt: 500 } })

Initially, this query returns in milliseconds. But as your catalog grows to hundreds of thousands of products, response times balloon to several seconds. What happened?

Without an index, MongoDB must perform a collection scan — it reads every document in the collection, checks the category and price fields, and only then returns the matching ones. This is inefficient and doesn't scale. Indexes solve this by creating a sorted data structure (a B-tree) that allows MongoDB to jump directly to the relevant documents, just like the index at the back of a book helps you find pages without reading the whole book.

Pro tip: The .explain("executionStats") method is your best friend. It reveals whether MongoDB is using an index or scanning the entire collection — the first step to spotting a missing index.

Core concept / mental model

Think of indexes as a phone book at a library. Without an index, MongoDB is like a librarian who must walk through every aisle, open every book, and check each page to find what you asked for. With an index, it's like having a card catalog: you look up the topic, get the exact shelf location, and walk straight to the book. The cost? Every time you add, update, or delete a document, MongoDB must also update the index — just like a librarian must add a new card when a book arrives.

In MongoDB, an index is a special data structure that stores a small portion of the collection's data set in an easy-to-traverse form. It stores the value of a specific field or set of fields, ordered by the value of the field. This allows MongoDB to search efficiently, reducing the number of documents it must examine.

Key terms

  • Index key(s): The field(s) on which the index is built.
  • Collation: Rules for string comparison (e.g., case-insensitive).
  • Selectivity: How uniquely an index value identifies a document. High selectivity means fewer documents match.
  • Compound index: An index on multiple fields, e.g., { category: 1, price: 1 }.
  • Covered query: When all fields in a query are part of an index, MongoDB can return results without fetching documents.

How it works step by step

Let's walk through the process of identifying a slow query, creating an index, and verifying the improvement.

1. Detect a slow query

Use the explain() method to see the query execution plan:

db.products.find({ category: "electronics", price: { $lt: 500 } }).explain("executionStats")

Look for "stage": "COLLSCAN" — this indicates a full collection scan. Also note totalDocsExamined compared to nReturned. If huge numbers are examined but few are returned, an index is needed.

2. Create the index

Decide which fields to index. For this query, a compound index on category and price is ideal:

db.products.createIndex({ category: 1, price: 1 })

Here, 1 means ascending order; -1 would mean descending. Order matters for compound indexes — the most selective field should come first.

3. Verify the improvement

Run the same explain() again. You should see "stage": "IXSCAN" and a dramatic drop in totalDocsExamined. The query should now be much faster.

4. Keep an eye on index usage

MongoDB has a built-in query optimizer that picks the best index for each query. You don't have to hint which index to use — it will automatically choose the most efficient plan. But you can force an index with .hint() if needed (rare).

Hands-on walkthrough

Let's practice with a real example. Assume you have a products collection with 100,000 documents.

Step 1: Insert sample data (simplified)

for (let i = 0; i < 100000; i++) {
  db.products.insertOne({
    name: "Product" + i,
    category: ["electronics", "books", "clothing"][i % 3],
    price: Math.floor(Math.random() * 1000)
  });
}

Step 2: Check the query performance without an index

db.products.find({ category: "electronics", price: { $lt: 500 } }).explain("executionStats")

Look at executionStats — you'll likely see totalDocsExamined: 100000 and nReturned: ~16666, with stage: "COLLSCAN". This is slow.

Step 3: Create the index

db.products.createIndex({ category: 1, price: 1 })

Step 4: Re-run the query with explain

db.products.find({ category: "electronics", price: { $lt: 500 } }).explain("executionStats")

Now you should see stage: "IXSCAN", totalDocsExamined: 0 (because the index alone is enough to determine matches), and nReturned: ~16666. The query is faster.

Step 5: Compare read vs. write performance

Indexes speed up reads but slow down writes. Test with a quick insert loop:

console.time("insert with index");
for (let i = 0; i < 1000; i++) {
  db.products.insertOne({ name: "New", category: "test", price: 1 });
}
console.timeEnd("insert with index");

Compare this to a collection without indexes. You'll see slightly slower inserts, but the read gain usually outweighs this cost.

Compare options / when to choose what

Index type Use case When to choose it
Single-field index ({ field: 1 }) Simple equality queries When you filter on one field only
Compound index ({ field1: 1, field2: -1 }) Queries on multiple fields When queries filter/sort by multiple fields — put the most selective field first
Multikey index (e.g., on arrays) Fields that contain arrays When querying array elements
Text index Full-text search When you need $text queries for natural language
Hashed index Equality queries on large fields (e.g., long strings) When you only need equality and want even distribution

General rule: Create indexes for the queries you actually run, not for every field. Too many indexes slow down writes and consume storage.

Pro tip: Check slow query logs (db.getProfilingLevel()) or use MongoDB Atlas's Performance Advisor to discover missing indexes.

Troubleshooting & edge cases

Slow queries still after creating an index

  • Wrong field order in a compound index: if your query filters on price and category, but your index is { price: 1, category: 1 }, MongoDB may not use it efficiently. Ensure the first field matches the most selective filter.
  • Unused index: use .explain() to see if the index is actually used. If not, remove it (db.collection.dropIndex()) to avoid write overhead.
  • Low selectivity: indexing a field with only a few distinct values (e.g., is_active: true/false) won't speed up queries much — MongoDB may still scan many documents.

Index creation takes too long

  • Background creation: use the background: true option (though it's deprecated in MongoDB 4.2+ as all builds are background). Use db.collection.createIndex(..., { background: true }) if needed for older versions.
  • Build on a replica set: index builds are rolling by default — they won't block reads/writes.

Index size vs. performance

  • Large indexes consume memory. If your working set doesn't fit in RAM, you'll see disk reads. Keep indexes lean.

Common mistakes

  • Creating an index on every field — bloats storage and slows writes unnecessarily.
  • Using a single-field index when a compound index would serve multiple queries.
  • Forgetting that index order matters for compound indexes — { category: 1, price: 1 } is different from { price: 1, category: 1 }.
  • Ignoring .explain() — don't guess; analyze before and after.

What you learned & what's next

You've learned how to create indexes to speed up queries: you can now identify slow queries with explain(), choose the right index type, create indexes with createIndex(), and verify performance improvements. You understand the trade-off between read speed and write overhead, and you can recognize common index pitfalls.

In the next lesson, you'll build on this foundation by exploring advanced indexing techniques, such as partial indexes, TTL indexes, and geospatial indexes, to handle even more specialized query patterns.

Keep practicing: run explain() on your own collections, spot collection scans, and create indexes that make your queries fly!

Practice recap

Open your mongosh and run db.collection.createIndex({ field: 1 }) on a collection with several thousand documents that you query frequently. Use .explain('executionStats') before and after to compare totalDocsExamined and execution time. Then experiment with a compound index to see how field order affects performance.

Common mistakes

  • Creating an index on every field, which bloats storage and slows writes unnecessarily.
  • Using a single-field index when a compound index would better serve multi-field queries.
  • Forgetting that index key order matters for compound indexes — { category: 1, price: 1 } is not the same as { price: 1, category: 1 }.
  • Not checking .explain() before and after index creation, so you miss inefficiencies.

Variations

  1. Use MongoDB Atlas's Performance Advisor to automatically suggest indexes based on real query patterns.
  2. For read-heavy applications, consider covering indexes to avoid fetching documents entirely.
  3. Use partial indexes to index only a subset of documents matching a filter, reducing index size and write overhead.

Real-world use cases

  • E-commerce platform: index category and price to speed up product filtering and price ranges.
  • Log analytics: index timestamp to quickly query logs within a time window.
  • User search: create a text index on name fields to enable fast $text searches.

Key takeaways

  • Indexes transform collection scans into efficient lookups, dramatically speeding up queries.
  • Use compound indexes on fields you filter or sort together, with the most selective field first.
  • Always verify the impact with .explain('executionStats') — look for IXSCAN instead of COLLSCAN.
  • Indexes speed up reads but add write overhead, so create them only for actual query patterns.
  • Be mindful of index size and memory usage; too many indexes can hurt performance.
  • MongoDB's optimizer automatically picks the best index — you don't need to hint in most cases.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.