How to Create Mongodb Index
How to Create MongoDB Index Indexing is one of the most critical aspects of database performance optimization, and MongoDB is no exception. In a world where data volume grows exponentially and user expectations for speed are higher than ever, the ability to quickly retrieve information from a database can make or break an application’s success. MongoDB, as a leading NoSQL document-oriented databas
How to Create MongoDB Index
Indexing is one of the most critical aspects of database performance optimization, and MongoDB is no exception. In a world where data volume grows exponentially and user expectations for speed are higher than ever, the ability to quickly retrieve information from a database can make or break an applications success. MongoDB, as a leading NoSQL document-oriented database, provides powerful indexing capabilities that allow developers to dramatically improve query performance, reduce latency, and scale efficiently. However, creating the right indexwhether single-field, compound, text, geospatial, or hashedis not always intuitive. This comprehensive guide walks you through everything you need to know to create MongoDB indexes effectively, from foundational concepts to advanced best practices, real-world examples, and essential tools.
By the end of this tutorial, you will understand not only how to create indexes in MongoDB but also when and why to use each type, how to avoid common pitfalls, and how to monitor and maintain them for long-term performance. Whether you're a developer new to MongoDB or a seasoned database administrator looking to optimize an existing system, this guide delivers actionable, production-ready insights.
Step-by-Step Guide
Understanding MongoDB Indexes
Before diving into the mechanics of creating an index, its essential to understand what an index is and how it functions within MongoDB. An index is a special data structure that stores a small portion of the collections data in an easy-to-traverse form. Instead of scanning every document in a collection to find matching results, MongoDB can use an index to locate the relevant documents much fastersimilar to how a books index helps you find topics without reading every page.
MongoDB indexes are built on fields within documents. When you create an index on a field, MongoDB sorts the values of that field and stores references to the documents containing those values. This allows the database engine to quickly locate documents matching a query condition without performing a full collection scana process known as a collection scan or COLLSCAN, which is highly inefficient for large datasets.
By default, MongoDB automatically creates a unique index on the _id field for every collection. This index ensures that each document has a unique identifier and is used internally for many operations. However, for any other field you frequently query, sort, or filter on, you must explicitly create an index.
Prerequisites
Before creating indexes, ensure you have the following:
- A running MongoDB instance (Community or Enterprise edition)
- Access to the MongoDB shell (
mongosh) or a GUI tool like MongoDB Compass - Appropriate permissions to create indexes on the target database and collection
- A clear understanding of your query patterns (what fields are used in
find(),sort(), andaggregate()operations)
Its also recommended to perform index creation during off-peak hours in production environments, as index builds can be resource-intensive and temporarily impact performance.
Step 1: Identify Query Patterns
The foundation of effective indexing lies in understanding your applications query behavior. Analyze your most frequent queries. For example:
- Do you often search for users by email?
db.users.find({email: "user@example.com"}) - Do you sort products by price in descending order?
db.products.find().sort({price: -1}) - Do you filter orders by both status and date?
db.orders.find({status: "shipped", createdAt: {$gte: new Date()}})
Use MongoDBs explain() method to analyze query execution plans. For example:
db.users.find({email: "user@example.com"}).explain("executionStats")
Look for the stage field in the output. If you see COLLSCAN, it means MongoDB is scanning every document in the collectionthis is a strong signal that an index is needed.
Step 2: Create a Single-Field Index
The simplest type of index is a single-field index, which is created on one field only. To create a single-field index on the email field in the users collection, use the createIndex() method:
db.users.createIndex({email: 1})
The value 1 indicates an ascending index; -1 indicates descending. For most equality queries, ascending and descending behave similarly, but for sorting operations, the direction matters. For example, if you frequently sort by createdAt in descending order (newest first), create the index as:
db.users.createIndex({createdAt: -1})
MongoDB returns a response like:
{ "numIndexesBefore" : 2, "numIndexesAfter" : 3, "ok" : 1 }
This confirms the index was created successfully.
Step 3: Create a Compound Index
Compound indexes are created on multiple fields and are essential for queries that filter or sort on more than one field. The order of fields in a compound index is critical because MongoDB can only use the index efficiently if the query filters on the leftmost fields first.
For example, if your application frequently runs queries like:
db.orders.find({status: "pending", customerId: "C123"}).sort({orderDate: -1})
You should create a compound index in this order:
db.orders.createIndex({status: 1, customerId: 1, orderDate: -1})
Why this order? MongoDB can use this index for:
- Queries filtering on
statusonly - Queries filtering on
statusandcustomerId - Queries filtering on
status,customerId, and sorting byorderDate
However, it cannot efficiently support a query filtering only on customerId or orderDate, because those fields are not the leftmost in the index.
Always place the most selective field (the one with the highest cardinality) first in the index, followed by fields used for sorting, then other filtering fields.
Step 4: Create a Text Index
Text indexes support full-text search capabilities for string content. They are ideal for applications requiring search functionality like product descriptions, blog posts, or user profiles.
To create a text index on the description field:
db.products.createIndex({description: "text"})
You can also create a compound text index across multiple fields:
db.products.createIndex({
title: "text",
description: "text",
category: "text"
})
Once created, you can perform full-text searches using the $text operator:
db.products.find({$text: {$search: "wireless headphones"}})
Important: MongoDB allows only one text index per collection. If you need to search across multiple fields, include them all in a single compound text index.
Step 5: Create a Geospatial Index
Geospatial indexes are used for location-based queries, such as finding nearby restaurants or tracking delivery drivers. MongoDB supports two types: 2dsphere (for spherical geometry, recommended) and 2d (for flat, planar geometry).
Assuming your collection has a field named location that stores GeoJSON coordinates:
db.restaurants.createIndex({location: "2dsphere"})
Now you can query for documents within a radius:
db.restaurants.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [-73.99279, 40.719296]
},
$maxDistance: 1000
}
}
})
This returns all restaurants within 1,000 meters of the specified coordinates.
Step 6: Create a Hashed Index
Hashed indexes store the hash of a fields value and are primarily used for sharding. They provide good distribution of data across shards but are not suitable for range queries or sorting.
To create a hashed index on the userId field:
db.users.createIndex({userId: "hashed"})
Hashed indexes are ideal for queries that perform equality matches:
db.users.find({userId: 12345})
They are not useful for queries like userId: {$gt: 1000} or sorting by userId.
Step 7: Create a Unique Index
Unique indexes ensure that no two documents in a collection have the same value for the indexed field. This is commonly used for email addresses, usernames, or product SKUs.
To create a unique index on the email field:
db.users.createIndex({email: 1}, {unique: true})
If a document with a duplicate email is inserted, MongoDB will throw a duplicate key error. To handle existing duplicates before creating a unique index, you must first clean the data or use the dropDups option (deprecated in newer versions) or delete duplicates manually.
Step 8: Create a Partial Index
Partial indexes index only a subset of documents in a collection based on a filter expression. They are space-efficient and improve write performance by reducing the number of indexed documents.
For example, if you only need to query active users:
db.users.createIndex({email: 1}, {partialFilterExpression: {status: "active"}})
This index will only include documents where status is "active". Queries that filter on email and status: "active" will use this index efficiently. Queries filtering on email alone will not use it unless they also include the partial filter condition.
Step 9: Create a Sparse Index
Sparse indexes only include documents that have the indexed field. If a document does not contain the field, it is not included in the index. This is useful for optional fields that are not present in all documents.
db.users.createIndex({phone: 1}, {sparse: true})
This index will only contain documents with a phone field. It saves storage space and improves performance when many documents lack the field.
Note: Sparse indexes ignore documents with null values or missing fields. If you need to include documents with null values, do not use sparse indexes.
Step 10: Verify and Monitor Indexes
After creating indexes, verify they exist using:
db.users.getIndexes()
This returns an array of all indexes on the collection, including their names, keys, and options.
To monitor index usage and performance, use:
db.system.profile.find().sort({$natural: -1}).limit(5)
Or enable the database profiler:
db.setProfilingLevel(1, {slowms: 5})
This logs all queries taking longer than 5 milliseconds. Analyze the output to confirm your indexes are being used.
Use MongoDB Atlas or Compasss Performance Advisor to receive automated index recommendations based on slow queries.
Best Practices
1. Index Only What You Need
Every index consumes memory and disk space. It also adds overhead to write operations (insert, update, delete), because MongoDB must update each index whenever a document changes. Avoid creating indexes just in case. Instead, base your indexing strategy on actual query patterns and performance metrics.
2. Prioritize Selectivity
Selectivity refers to how well an index can narrow down results. A field with many unique values (e.g., email, user ID) is highly selective; a field with few values (e.g., gender, status) is not. Always place the most selective field first in compound indexes to maximize efficiency.
3. Use Compound Indexes Wisely
Remember the leftmost prefix rule: MongoDB can use a compound index for queries that match the leftmost fields in the index. For example, an index on {a: 1, b: 1, c: 1} can support queries on {a}, {a, b}, or {a, b, c}, but not {b} or {b, c}.
If you frequently query on {b} and {a, b}, consider creating two separate indexes: one on {b} and another on {a, b}.
4. Avoid Redundant Indexes
Dont create multiple indexes that serve the same purpose. For example, if you have an index on {a: 1, b: 1}, you dont need a separate index on {a: 1}the compound index can be used for queries on a alone.
Use db.collection.getIndexes() to audit existing indexes and remove duplicates or unused ones.
5. Monitor Index Size and Memory Usage
Indexes reside in RAM for optimal performance. If your working set (frequently accessed data and indexes) exceeds available RAM, performance will degrade due to disk I/O. Use MongoDB Compass or the db.serverStatus() command to monitor memory usage and index size.
For large collections, consider using capped collections, TTL indexes, or data archiving to reduce the overall index footprint.
6. Use Covered Queries
A covered query is one where all the fields in the query and the projection are part of the index. This allows MongoDB to satisfy the query entirely from the index without accessing the actual documents.
Example:
db.users.createIndex({email: 1, name: 1})
db.users.find({email: "user@example.com"}, {email: 1, name: 1, _id: 0})
The projection excludes _id and includes only fields in the index. Use .explain("executionStats") to confirm the query uses IXSCAN and not FETCH.
7. Avoid Indexing Fields with Low Cardinality
Indexing fields like isActive (true/false) or country (limited set of values) is rarely beneficial. The index will be large but provide little filtering power. In such cases, a full collection scan may be faster.
8. Use Text Indexes Sparingly
Text indexes are large and slow to build. They are also not suitable for high-frequency real-time searches. For applications requiring advanced search features (fuzzy matching, synonyms, ranking), consider integrating a dedicated search engine like Elasticsearch or Algolia.
9. Rebuild Indexes Periodically
Over time, indexes can become fragmented due to frequent updates and deletions. In MongoDB 4.4+, you can rebuild an index using:
db.users.reIndex()
This drops and recreates all indexes on the collection. Use with caution in productionperform during maintenance windows.
10. Test Indexes in Staging First
Always test index creation and performance impact on a staging environment that mirrors production data volume and query patterns. Monitor CPU, memory, and I/O during index creation to anticipate resource requirements.
Tools and Resources
MongoDB Compass
MongoDB Compass is the official GUI for MongoDB. It provides an intuitive interface to view collections, run queries, and analyze query execution plans. The Performance tab includes a Performance Advisor that suggests indexes based on slow queries. It also visualizes index usage and helps identify unused indexes.
MongoDB Atlas
Atlas is MongoDBs fully managed cloud database service. It includes advanced monitoring, automated index recommendations, performance metrics, and alerting. The Performance Advisor in Atlas analyzes queries over time and recommends indexes with one-click creation.
MongoDB Cloud Manager / Ops Manager
For on-premises deployments, MongoDB Ops Manager provides comprehensive monitoring, backup, and automation tools. It includes index performance analytics and query profiling capabilities.
MongoDB Shell (mongosh)
The command-line interface remains indispensable for scripting, automation, and quick diagnostics. Use explain(), getIndexes(), and db.collection.stats() to gather detailed information about collection and index performance.
Third-Party Tools
- MongoDB Atlas Data Lake For querying data across MongoDB and S3 with SQL
- Studio 3T A feature-rich GUI with query builder, index designer, and performance analyzer
- MongoDB Charts For visualizing data trends and identifying query bottlenecks
Documentation and Learning Resources
- MongoDB Official Index Documentation
- MongoDB University (Free Courses)
- MongoDB Blog Performance Optimization
- MongoDB GitHub Repository
Monitoring and Alerting
Integrate MongoDB with tools like Prometheus and Grafana using the MongoDB Exporter to monitor index-related metrics such as:
- Index hit rate
- Memory usage by index
- Query execution time
- Number of documents scanned vs. indexed
Set alerts for high collection scan ratios or index build durations to proactively address performance issues.
Real Examples
Example 1: E-Commerce Product Search
Scenario: You run an e-commerce platform with millions of products. Users frequently search by category, price range, and sort by rating.
Query pattern:
db.products.find({
category: "electronics",
price: {$gte: 100, $lte: 500}
}).sort({rating: -1})
Optimal index:
db.products.createIndex({
category: 1,
price: 1,
rating: -1
})
Why this works:
categoryis highly selective (many categories)priceis used in a range queryMongoDB can use the index for range scansratingis sorted in descending order, matching the index direction
Without this index, MongoDB performs a full collection scan, which can take seconds on large datasets. With the index, response time drops to under 100ms.
Example 2: User Authentication System
Scenario: You need to authenticate users by email and check if their account is active.
Query:
db.users.findOne({
email: "john@example.com",
status: "active"
})
Optimal index:
db.users.createIndex({email: 1, status: 1}, {unique: true})
Additional optimization: Since you only need to verify existence, use a covered query:
db.users.findOne(
{email: "john@example.com", status: "active"},
{email: 1, _id: 0}
)
Now the query reads only from the indexno document fetch is needed.
Example 3: Location-Based Delivery Service
Scenario: A food delivery app needs to find nearby restaurants.
Document structure:
{
_id: ObjectId("..."),
name: "Pizza Palace",
location: {
type: "Point",
coordinates: [-73.9857, 40.7484]
}
}
Index:
db.restaurants.createIndex({location: "2dsphere"})
Query:
db.restaurants.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [-73.9857, 40.7484]
},
$maxDistance: 2000
}
}
})
With the 2dsphere index, this query returns results in under 50ms, even with hundreds of thousands of restaurants.
Example 4: Log Analysis System
Scenario: You store application logs and need to search by timestamp and error level.
Query:
db.logs.find({
level: "ERROR",
timestamp: {$gte: ISODate("2024-01-01T00:00:00Z")}
}).sort({timestamp: 1})
Optimal index:
db.logs.createIndex({
level: 1,
timestamp: 1
})
Since level has low cardinality (only a few values), this index may seem inefficient. However, because its combined with a high-selectivity timestamp field, and you always query both together, its optimal.
Consider adding a partial index if you only care about recent logs:
db.logs.createIndex({
level: 1,
timestamp: 1
}, {
partialFilterExpression: {
timestamp: {$gte: ISODate("2024-01-01T00:00:00Z")}
}
})
FAQs
Can I create an index on a nested field in MongoDB?
Yes. Use dot notation. For example, if you have a document like {user: {name: "John", email: "john@example.com"}}, create an index on user.email:
db.users.createIndex({"user.email": 1})
How do I know if an index is being used?
Use the explain() method. Look for "stage": "IXSCAN" in the output. If you see "stage": "COLLSCAN", the index is not being used.
Can I create an index on an array field?
Yes. MongoDB creates a multikey index automatically when you index a field containing an array. Each element in the array becomes a separate index entry. For example:
db.posts.createIndex({tags: 1})
This allows efficient queries like db.posts.find({tags: "mongodb"}).
What happens if I create a duplicate index?
MongoDB will return an error if you try to create an index with the same key pattern and options. If the options differ (e.g., one is sparse and the other isnt), MongoDB treats them as separate indexes. However, this can lead to redundancy and performance degradation. Always audit your indexes using getIndexes().
Do indexes slow down write operations?
Yes. Every insert, update, or delete must also update all relevant indexes. The more indexes you have, the slower writes become. This is why its critical to index only fields that are frequently queried.
How long does it take to build an index?
Index build time depends on collection size, available RAM, disk speed, and whether the operation runs in the foreground or background. For large collections, it can take minutes to hours. Use the {background: true} option to allow reads and writes during index creation:
db.users.createIndex({email: 1}, {background: true})
Can I drop an index without restarting MongoDB?
Yes. Use the dropIndex() method:
db.users.dropIndex("email_1")
Replace "email_1" with the actual index name, which you can find using getIndexes().
Are indexes automatically maintained in MongoDB?
Yes. MongoDB automatically updates indexes when documents are inserted, updated, or deleted. You do not need to manually rebuild them unless fragmentation becomes severe or you are changing the index structure.
Whats the maximum number of indexes per collection?
MongoDB allows up to 64 indexes per collection. While this is generous, exceeding 1015 indexes is usually a sign of poor indexing strategy. Focus on quality over quantity.
Can I create an index on the _id field?
You cannot create a new index on _id because MongoDB automatically creates a unique index on it for every collection. Attempting to do so will result in an error.
Conclusion
Creating MongoDB indexes is not just a technical taskits a strategic decision that directly impacts the scalability, responsiveness, and cost-efficiency of your applications. A well-designed indexing strategy transforms slow, unresponsive queries into fast, predictable operations. Conversely, poor indexing leads to resource exhaustion, high latency, and frustrated users.
In this guide, youve learned how to identify the right fields to index, how to create various types of indexesincluding single-field, compound, text, geospatial, and hashedhow to optimize them using best practices, and how to monitor their performance using real tools and examples. Youve also seen how indexing decisions must be guided by actual query patterns, not assumptions.
Remember: Indexes are not a set it and forget it feature. As your data and usage evolve, so should your indexes. Regularly review slow queries, audit unused indexes, and test new index strategies in staging environments. Leverage MongoDBs built-in tools like the Performance Advisor and explain() output to make data-driven decisions.
Ultimately, mastering MongoDB indexing empowers you to build applications that scale gracefully under load, deliver real-time experiences, and remain maintainable as your data grows. Start small, measure everything, and optimize iteratively. The performance gains you achieve will be well worth the investment.