MongoDB Single Field Indexes
Introduction
When working with MongoDB databases, query performance is crucial, especially as your data grows. One of the most fundamental optimization techniques in MongoDB is creating indexes. Single field indexes are the simplest and most common type of index in MongoDB.
In this tutorial, you'll learn how single field indexes work, when to use them, and how they can dramatically improve your query performance.
What are Single Field Indexes?
A single field index is exactly what it sounds like – an index created on a single field of a document in a MongoDB collection. Similar to an index in a book that helps you quickly locate specific information, a MongoDB index helps the database efficiently locate documents without scanning every document in a collection.
Without indexes, MongoDB must perform a collection scan, checking every document to find matches to your query. As your collection grows, this becomes increasingly inefficient.
Creating a Single Field Index
The basic syntax for creating a single field index is:
db.collection.createIndex({ field: 1 })
Where:
field
is the name of the field you want to index1
indicates an ascending index-1
would indicate a descending index
Example: Creating a Basic Index
Let's say we have a users
collection with millions of documents, and we frequently query by email
:
// Create an ascending index on the email field
db.users.createIndex({ email: 1 })
The output will be something like:
{
"createdCollectionAutomatically": false,
"numIndexesBefore": 1,
"numIndexesAfter": 2,
"ok": 1
}
MongoDB automatically creates an index on the _id
field, which is why numIndexesBefore
is 1 even if you haven't created any other indexes.
Understanding Index Direction (Ascending vs Descending)
When creating a single field index, you can specify whether the index should be ascending (1) or descending (-1):
// Ascending index
db.products.createIndex({ price: 1 })
// Descending index
db.products.createIndex({ price: -1 })
For single field indexes, the direction (ascending or descending) doesn't matter for simple equality queries. However, the direction becomes important when:
- You're sorting results
- You're creating compound indexes (indexes on multiple fields)
For example, if you frequently sort products by price in descending order, using a descending index can be more efficient:
// Query that benefits from descending price index
db.products.find().sort({ price: -1 })
Examining Index Usage
To verify if your queries are using indexes, use the explain()
method:
db.users.find({ email: "[email protected]" }).explain("executionStats")
This will show detailed information about the query execution, including:
- Whether an index was used
- How many documents were examined
- How long the query took
Look for "IXSCAN"
in the winningPlan.stage
field to confirm index usage.
Real-World Applications
Let's look at some practical scenarios where single field indexes are valuable:
Example 1: E-commerce Product Search
In an e-commerce application, users often search for products by name:
// Create the collection with example products
db.products.insertMany([
{ name: "Laptop", category: "Electronics", price: 999 },
{ name: "Headphones", category: "Electronics", price: 199 },
{ name: "Coffee Maker", category: "Kitchen", price: 89 },
// Imagine thousands more products
])
// Create an index on the product name
db.products.createIndex({ name: 1 })
// Now searching by name will be efficient
db.products.find({ name: "Laptop" })
Example 2: User Authentication
For a login system, we need to quickly find users by email:
// Create an index on the email field
db.users.createIndex({ email: 1 }, { unique: true })
// This query will now be very efficient
db.users.findOne({ email: "[email protected]" })
Notice the unique: true
option, which ensures no two users can have the same email address.
Example 3: Time-series Data
For time-series data like logs or events, creating an index on the timestamp field is essential:
// Create an index on timestamp
db.logs.createIndex({ timestamp: -1 })
// Efficiently query recent logs
db.logs.find({
timestamp: { $gte: ISODate("2023-01-01"), $lt: ISODate("2023-01-02") }
}).sort({ timestamp: -1 })
Index Options
When creating single field indexes, you can specify various options:
Unique Indexes
Ensures all values for the indexed field are unique:
db.users.createIndex({ username: 1 }, { unique: true })
Attempting to insert a document with an existing username will result in an error.
Sparse Indexes
Only includes documents that have the indexed field:
db.customers.createIndex({ premium_membership_id: 1 }, { sparse: true })
This is useful for fields that aren't present in all documents.
TTL (Time-To-Live) Indexes
Automatically removes documents after a specified period:
// Remove session documents after 1 hour (3600 seconds)
db.sessions.createIndex({ last_activity: 1 }, { expireAfterSeconds: 3600 })
This is perfect for sessions, temporary data, or logs.
Partial Indexes
Indexes only a subset of documents in a collection:
// Index only active products
db.products.createIndex(
{ name: 1 },
{ partialFilterExpression: { status: "active" } }
)
Index Performance Considerations
While indexes speed up queries, they come with trade-offs:
-
Write Performance: Each index must be updated when documents are modified, which slows down write operations.
-
Storage Space: Indexes consume additional disk space.
-
Index Selectivity: Indexes work best on fields with high "selectivity" (many different values).
For example, indexing a "gender" field (with only a few possible values) may not be efficient if the collection has millions of documents but only 2-3 possible gender values.
Monitoring Index Usage
To see which indexes exist on a collection:
db.collection.getIndexes()
To see statistics about index usage:
db.collection.stats().indexSizes
MongoDB also provides the $indexStats
aggregation stage for detailed index usage statistics:
db.collection.aggregate([
{ $indexStats: {} }
])
When to Use Single Field Indexes
Single field indexes are ideal when:
- You frequently query a collection by a specific field
- The field has high selectivity (many unique values)
- Your queries return a small subset of the total documents
- You need to enforce uniqueness on a field
When to Use Other Index Types
While single field indexes are powerful, there are cases where other index types are more appropriate:
- Compound indexes: When you frequently query by multiple fields together
- Multikey indexes: For arrays
- Text indexes: For text search
- Geospatial indexes: For location-based queries
- Hashed indexes: For specific sharding strategies
We'll cover these in separate tutorials.
Summary
Single field indexes are a fundamental optimization technique in MongoDB that can dramatically improve query performance. In this tutorial, you learned:
- How to create single field indexes
- The difference between ascending and descending indexes
- How to verify index usage with
explain()
- Real-world applications for single field indexes
- Various index options like unique, sparse, TTL, and partial indexes
- Performance considerations when using indexes
By strategically adding single field indexes to your MongoDB collections, you can significantly improve your application's performance, especially as your dataset grows.
Exercises
To practice what you've learned:
- Create a collection with at least 1000 documents, each with several fields
- Run some queries without indexes and note the execution time
- Add appropriate single field indexes
- Run the same queries again and compare the performance
- Use
explain()
to analyze query execution with and without indexes
Additional Resources
- MongoDB Official Documentation on Indexes
- MongoDB Index Strategies
- Query Performance Optimization in MongoDB
Happy indexing!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)