How to Create Mongodb Index
How to Create MongoDB Index MongoDB is a powerful, scalable NoSQL database widely used in modern applications for its flexibility, performance, and ease of integration with development frameworks. However, as datasets grow, query performance can degrade significantly without proper indexing. Creating MongoDB indexes is one of the most critical actions a developer or database administrator can take
How to Create MongoDB Index
MongoDB is a powerful, scalable NoSQL database widely used in modern applications for its flexibility, performance, and ease of integration with development frameworks. However, as datasets grow, query performance can degrade significantly without proper indexing. Creating MongoDB indexes is one of the most critical actions a developer or database administrator can take to optimize read operations, reduce latency, and ensure efficient data retrieval. This comprehensive guide walks you through everything you need to know about creating MongoDB indexesfrom the fundamentals to advanced techniques, best practices, real-world examples, and essential tools. Whether you're new to MongoDB or looking to refine your indexing strategy, this tutorial will equip you with the knowledge to build high-performing database systems.
Step-by-Step Guide
Understanding MongoDB Indexes
Before creating indexes, its essential to understand what they are and how they function. In MongoDB, an index is a data structure that improves the speed of data retrieval operations on a collection. Without an index, MongoDB must perform a collection scanreading every document in a collection to find those matching a query. This process becomes prohibitively slow as the dataset grows. Indexes work similarly to the index of a book: instead of reading every page, you look up the topic in the index and jump directly to the relevant pages.
MongoDB supports multiple types of indexes, including:
- Single Field Index
- Compound Index
- Multikey Index
- Text Index
- Geospatial Index
- Hashed Index
- TTL Index
Each index type serves a specific use case. For example, a single field index is ideal for queries filtering on one field, while a compound index is used when filtering on multiple fields simultaneously.
Prerequisites
Before you begin 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
- Write permissions to the target database and collection
- A basic understanding of MongoDB query syntax
If you're using MongoDB Atlas, the cloud-hosted version, you can access the shell directly from the web interface or connect via the MongoDB Compass GUI.
Step 1: Identify Query Patterns
The first step in creating effective indexes is analyzing your applications query patterns. Review the most frequently executed queries in your application. Look for:
- Fields used in
find(),sort(), andaggregate()operations - Fields used in equality matches, range queries, or sorting
- Queries that return large result sets or take longer than 100ms
Use MongoDBs explain() method to analyze query performance. For example:
db.users.find({ email: "john@example.com" }).explain("executionStats")
This returns detailed statistics, including whether an index was used, the number of documents scanned, and execution time. If stage shows COLLSCAN, your query is performing a collection scanindicating the need for an index.
Step 2: Create a Single Field Index
The simplest index type is the single field index. It is created on one field in a document. To create a single field index on the email field in the users collection:
db.users.createIndex({ email: 1 })
The value 1 specifies an ascending index; use -1 for descending. For most use cases, ascending is preferred unless you frequently sort in descending order.
You can also create an index on a nested field. For example, if your documents have a structure like:
{
"_id": ObjectId("..."),
"profile": {
"firstName": "John",
"lastName": "Doe"
}
}
To index the profile.firstName field:
db.users.createIndex({ "profile.firstName": 1 })
Step 3: Create a Compound Index
A compound index combines two or more fields. This is essential when your queries filter on multiple fields. For example, if you often run queries like:
db.users.find({ city: "New York", status: "active" }).sort({ createdAt: -1 })
Create a compound index that covers all three fields:
db.users.createIndex({ city: 1, status: 1, createdAt: -1 })
Order matters in compound indexes. MongoDB can use the index for queries that match the leftmost prefix of the index. So the above index can be used for:
{ city: "New York" }{ city: "New York", status: "active" }{ city: "New York", status: "active", createdAt: { $gt: ... } }
But it cannot be used for:
{ status: "active" }missing the leftmost field{ createdAt: -1 }missing the first two fields
Always place the most selective field (the one with the highest cardinality) first in the compound index to maximize efficiency.
Step 4: Create a Multikey Index
Multikey indexes are automatically created when you index a field that contains an array. For example, if users have tags:
{
"_id": ObjectId("..."),
"name": "Alice",
"tags": ["developer", "mongodb", "nodejs"]
}
Creating an index on tags:
db.users.createIndex({ tags: 1 })
MongoDB automatically creates a multikey index, indexing each element in the array. This allows efficient queries like:
db.users.find({ tags: "mongodb" })
Multikey indexes support queries that match any element in the array, making them ideal for tagging and categorization systems.
Step 5: Create a Text Index
Text indexes enable full-text search capabilities in MongoDB. They are useful for searching string content across one or more fields. To create a text index on the description field:
db.products.createIndex({ description: "text" })
Once created, you can perform text searches using the $text operator:
db.products.find({ $text: { $search: "wireless headphones" } })
To create a text index on multiple fields:
db.products.createIndex({
title: "text",
description: "text",
category: "text"
})
Text indexes are case-insensitive and ignore common stop words (like the, and, or). You can also specify a default language to control stemming and tokenization:
db.products.createIndex({
title: "text",
description: "text"
}, { default_language: "english" })
Step 6: Create a Geospatial Index
For location-based queries, MongoDB supports 2dsphere and 2d indexes. A 2dsphere index is used for Earth-sphere geometry (latitude/longitude coordinates). For example, if your documents contain location data:
{
"_id": ObjectId("..."),
"name": "Coffee Shop",
"location": {
"type": "Point",
"coordinates": [-73.9928, 40.7193]
}
}
Create a 2dsphere index:
db.locations.createIndex({ location: "2dsphere" })
Then query for documents within a radius:
db.locations.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [-73.9928, 40.7193]
},
$maxDistance: 1000
}
}
})
This finds all locations within 1000 meters of the specified point.
Step 7: Create a Hashed Index
Hashed indexes are used for sharding and are particularly useful when you need to distribute data evenly across shards. They store the hash of the field value rather than the value itself. Hashed indexes are not suitable for range queries but are excellent for equality matches.
To create a hashed index on the userId field:
db.users.createIndex({ userId: "hashed" })
This index is commonly used in sharded clusters to ensure even data distribution across shards.
Step 8: Create a TTL Index
TTL (Time-To-Live) indexes automatically remove documents after a specified number of seconds. They are ideal for logs, sessions, or temporary data.
First, ensure your field is a Date type:
{
"_id": ObjectId("..."),
"sessionId": "abc123",
"createdAt": ISODate("2024-06-01T10:00:00Z")
}
Create a TTL index that expires after 3600 seconds (1 hour):
db.sessions.createIndex({ "createdAt": 1 }, { expireAfterSeconds: 3600 })
MongoDB runs a background task every 60 seconds to remove expired documents. Note: TTL indexes do not guarantee immediate deletion.
Step 9: Verify Index Creation
After creating an index, verify it exists:
db.users.getIndexes()
This returns an array of all indexes on the collection, including system indexes. Look for your newly created index in the list.
To check if an index is being used by a query, use the explain() method again:
db.users.find({ email: "john@example.com" }).explain("executionStats")
If the output shows IXSCAN under the stage field, the index is being utilized.
Step 10: Drop or Rebuild Indexes (When Necessary)
If an index is no longer needed or is causing performance issues, drop it:
db.users.dropIndex("email_1")
Replace email_1 with the index name as shown in getIndexes(). To drop all indexes except the default _id index:
db.users.dropIndexes()
Rebuilding indexes may be necessary after bulk data imports or schema changes. Use:
db.users.reIndex()
Be cautious: reindexing locks the collection and can impact performance on large datasets.
Best Practices
Index Only What You Need
Every index consumes memory and disk space. More importantly, each index adds overhead to write operations (inserts, updates, deletes), as MongoDB must update the index structure each time a document changes. Avoid creating indexes on every field. Focus on fields used in queries, sorts, and joins.
Use Compound Indexes Strategically
Always order fields in a compound index based on selectivity and query patterns. Place the most selective field first. For example, if you frequently query by status and email, and email has higher cardinality (nearly unique), put email first:
db.users.createIndex({ email: 1, status: 1 })
This index can also be used for queries on email alone, but not for status alone.
Avoid Over-Indexing
Having too many indexes can slow down write performance and increase storage costs. Monitor index usage with:
db.collection.aggregate([ { $indexStats: {} } ])
This returns usage statistics for each index, including the number of accesses. If an index has zero hits over several days, consider dropping it.
Use Covered Queries
A covered query is one where all fields in the query and projection are part of the index. This allows MongoDB to satisfy the query using only the index, without accessing the actual documents.
Example:
db.users.createIndex({ email: 1, name: 1 })
db.users.find({ email: "john@example.com" }, { email: 1, name: 1, _id: 0 })
Here, the query filters on email and projects only email and nameboth included in the index. The explain() output will show "stage": "IXSCAN" with no FETCH stage, indicating a covered query.
Index Sorting Fields
If you frequently sort results, include the sort field in your index. For example:
db.orders.find({ customerId: "C123" }).sort({ orderDate: -1 })
Create an index:
db.orders.createIndex({ customerId: 1, orderDate: -1 })
This allows MongoDB to retrieve and sort results in a single operation.
Monitor Index Size and Memory Usage
Large indexes can consume significant RAM. Use:
db.collection.stats()
to check the size of indexes versus the collection. If indexes are larger than available RAM, performance will degrade due to disk I/O.
Use Background Index Builds for Production
By default, index creation blocks other operations on the collection. For production databases, use the background option:
db.users.createIndex({ email: 1 }, { background: true })
This allows reads and writes to continue while the index is built. However, background builds take longer and use more system resources.
Limit the Number of Indexes per Collection
MongoDB allows a maximum of 64 indexes per collection. Plan your indexing strategy accordingly. Prioritize indexes that deliver the highest performance gains.
Test Indexes in Staging
Always test index changes in a staging environment that mirrors production. Measure query performance before and after index creation. Use tools like MongoDB Atlas Performance Advisor or custom scripts to log execution times.
Consider Index Prefixes
When designing compound indexes, think about how queries will use the leftmost prefix. For example, if you have:
db.orders.createIndex({ customerId: 1, status: 1, orderDate: -1 })
This index can serve:
{ customerId: "C123" }{ customerId: "C123", status: "shipped" }{ customerId: "C123", status: "shipped", orderDate: { $gt: ... } }
But not { status: "shipped" } or { orderDate: { $gt: ... } }. Design your indexes to match your most common query patterns.
Tools and Resources
MongoDB Compass
MongoDB Compass is the official GUI for MongoDB. It provides a visual interface to analyze query performance, view index usage, and create or drop indexes without writing code. Use the Indexes tab to inspect existing indexes and the Performance tab to identify slow queries and receive index recommendations.
MongoDB Atlas Performance Advisor
If youre using MongoDB Atlas (the cloud-hosted version), the Performance Advisor automatically monitors your queries and suggests indexes that could improve performance. It provides a clear Create Index button with the recommended index specification.
mongosh (MongoDB Shell)
The modern MongoDB shell (mongosh) is the primary tool for interacting with MongoDB. It supports all indexing commands and integrates with scripting for automation. Use it to batch-create indexes or verify index usage programmatically.
MongoDB EXPLAIN Output
Always use explain("executionStats") to analyze query plans. It reveals whether your index is being used, how many documents were scanned, and the execution time. This is essential for validating index effectiveness.
Index Usage Statistics
Use the $indexStats aggregation stage to monitor index usage:
db.users.aggregate([ { $indexStats: {} } ])
This returns a document for each index, showing the number of accesses, hits, and misses. Indexes with zero accesses over time are candidates for deletion.
Third-Party Monitoring Tools
Tools like Datadog, New Relic, and Prometheus with MongoDB exporters can track query latency, index efficiency, and system resource usage over time. Integrate them into your DevOps pipeline for continuous performance monitoring.
Official MongoDB Documentation
Always refer to the official MongoDB documentation for the latest syntax, supported features, and version-specific behavior. The documentation is comprehensive and includes examples for all index types: https://www.mongodb.com/docs/manual/indexes/
Online Index Simulators
Some community tools and sandbox environments allow you to simulate query performance with different index configurations. While not official, they can be helpful for learning and experimentation.
Real Examples
Example 1: E-Commerce Product Search
Scenario: You run an e-commerce platform with a products collection. Common queries include:
- Find products by category and price range
- Sort by price ascending or descending
- Search product names using keywords
Documents look like:
{
"_id": ObjectId("..."),
"name": "Wireless Headphones",
"category": "Electronics",
"price": 99.99,
"tags": ["audio", "wireless", "bluetooth"],
"description": "High-quality wireless headphones with noise cancellation."
}
Recommended indexes:
// Index for category + price range queries
db.products.createIndex({ category: 1, price: 1 })
// Index for sorting by price
db.products.createIndex({ price: -1 })
// Text index for name and description search
db.products.createIndex({
name: "text",
description: "text"
}, { default_language: "english" })
// Multikey index for tag-based filtering
db.products.createIndex({ tags: 1 })
Query example:
db.products.find({
category: "Electronics",
price: { $gte: 50, $lte: 150 }
}).sort({ price: 1 })
This query uses the { category: 1, price: 1 } index to filter and sort efficiently.
Example 2: User Activity Logging
Scenario: You log user login events in a login_logs collection. Each document includes a timestamp and user ID. You need to:
- Find all logins for a specific user
- Retrieve recent logins (last 7 days)
- Automatically delete logs older than 30 days
Documents:
{
"_id": ObjectId("..."),
"userId": "U789",
"ipAddress": "192.168.1.1",
"loginTime": ISODate("2024-06-05T08:22:15Z")
}
Recommended indexes:
// Index for user-based queries
db.login_logs.createIndex({ userId: 1 })
// TTL index to auto-delete logs after 30 days (2,592,000 seconds)
db.login_logs.createIndex({ loginTime: 1 }, { expireAfterSeconds: 2592000 })
Query example:
db.login_logs.find({ userId: "U789", loginTime: { $gte: ISODate("2024-05-29T00:00:00Z") } })
The index on userId enables fast filtering, and the TTL index ensures automatic cleanup.
Example 3: Location-Based Social App
Scenario: A social app allows users to find nearby friends. Each user document contains a geospatial location.
Documents:
{
"_id": ObjectId("..."),
"username": "alex_123",
"location": {
"type": "Point",
"coordinates": [-73.9857, 40.7484]
}
}
Recommended index:
db.users.createIndex({ location: "2dsphere" })
Query to find users within 5 km:
db.users.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [-73.9857, 40.7484]
},
$maxDistance: 5000
}
}
})
This query leverages the 2dsphere index for efficient geospatial searching.
Example 4: High-Volume Analytics Dashboard
Scenario: A dashboard displays real-time metrics based on user actions. Queries group by date and user segment.
Documents:
{
"_id": ObjectId("..."),
"userId": "U101",
"eventType": "page_view",
"timestamp": ISODate("2024-06-05T10:00:00Z"),
"region": "North America"
}
Common query:
db.events.aggregate([
{ $match: { region: "North America", timestamp: { $gte: start, $lt: end } } },
{ $group: { _id: "$eventType", count: { $sum: 1 } } }
])
Recommended index:
db.events.createIndex({ region: 1, timestamp: 1 })
This index allows the $match stage to use the index for filtering, reducing the number of documents passed to the aggregation pipeline.
FAQs
Can I create an index on a field that doesnt exist in all documents?
Yes. MongoDB indexes documents that have the indexed field. Documents without the field are not included in the index. This is safe and common in flexible schemas.
Do indexes slow down writes?
Yes. Every insert, update, or delete requires MongoDB to update all relevant indexes. This overhead increases with the number of indexes. Balance read performance gains with write overhead.
How do I know if an index is being used?
Use the explain() method. If the output shows IXSCAN (index scan), the index is being used. If it shows COLLSCAN, the query is performing a collection scan and needs an index.
Can I create an index on a nested field?
Yes. Use dot notation. For example, { "profile.city": 1 } indexes the city field inside the profile object.
What happens if I create the same index twice?
MongoDB ignores duplicate index creation. If an index with the same specification already exists, the command returns successfully but does nothing.
Are indexes automatically updated?
Yes. MongoDB maintains indexes automatically as documents are inserted, updated, or deleted. No manual intervention is required.
Can I use indexes with aggregation pipelines?
Yes. MongoDB can use indexes during the $match and $sort stages of an aggregation pipeline. Ensure your index supports the fields used in these stages.
What is the difference between a 2d and 2dsphere index?
A 2d index is for flat, planar geometry and is suitable for small areas or simple coordinates. A 2dsphere index is for spherical geometry and accurately calculates distances on Earths surface. Use 2dsphere for real-world location data.
How often should I review my indexes?
Review indexes quarterly or after major application changes. Use $indexStats and query performance logs to identify underused or redundant indexes.
Can I create an index on a field with a large number of unique values?
Yes. High-cardinality fields (like email addresses or UUIDs) are excellent candidates for indexing because they reduce the number of documents MongoDB must examine.
Conclusion
Creating effective MongoDB indexes is not just a technical taskits a strategic decision that directly impacts the scalability, responsiveness, and cost-efficiency of your application. From single-field indexes to complex compound and geospatial structures, each type serves a unique purpose. The key to success lies in understanding your query patterns, avoiding over-indexing, and continuously monitoring performance.
By following the step-by-step guide in this tutorial, applying the best practices outlined, and leveraging the recommended tools, you can transform slow, resource-heavy queries into fast, optimized operations. Real-world examples demonstrate how indexing strategies align with business needs, whether youre building an e-commerce platform, a location-based app, or a high-volume analytics system.
Remember: indexing is not a one-time setup. As your data and queries evolve, so should your indexes. Regularly audit your index usage, drop unused indexes, and test new ones in staging environments before deploying to production. With thoughtful indexing, MongoDB can handle millions of documents with sub-second response timeseven under heavy load.
Start by analyzing your slowest queries today. Create one targeted index. Measure the improvement. Then iterate. The cumulative effect of well-designed indexes is profoundyour users will notice the difference, and your infrastructure will thank you.