MongoDB Index Properties
MongoDB indexes are essential for improving query efficiency. But beyond just creating standard indexes, MongoDB offers various index properties that let you customize how indexes work and what data they include. Understanding these properties can help you create more efficient indexes tailored to your application's needs.
Introduction to Index Properties
In MongoDB, an index doesn't have to be just a simple ordered reference to your document fields. You can configure indexes with special behaviors and constraints to match your specific requirements. These properties provide fine-grained control over your indexes and can help optimize both performance and data integrity.
This guide covers the most important index properties in MongoDB:
- Unique Indexes
- Sparse Indexes
- Partial Indexes
- TTL Indexes
- Hidden Indexes
- Collation
Let's explore each of these properties and how they can benefit your application.
Unique Indexes
Unique indexes ensure that the indexed fields don't store duplicate values. This property is essential when you need to enforce uniqueness in your data, such as for usernames or email addresses.
Creating a Unique Index
To create a unique index, use the createIndex()
method with the unique
property set to true
:
db.users.createIndex({ email: 1 }, { unique: true })
This command creates an ascending index on the email
field and ensures that all email values in the collection are unique.
Example: Handling Duplicate Key Errors
If you try to insert a document with a duplicate value in a unique index, MongoDB will return a duplicate key error:
// First insert
db.users.insertOne({ name: "John", email: "[email protected]" })
// Result: Successfully inserted
// Second insert with the same email
db.users.insertOne({ name: "Jane", email: "[email protected]" })
// Result: MongoError: E11000 duplicate key error collection: test.users index: email_1 dup key: { email: "[email protected]" }
Unique Compound Indexes
You can also create unique indexes on multiple fields, which ensures that the combination of values is unique:
db.products.createIndex({ category: 1, sku: 1 }, { unique: true })
This allows the same sku
to appear in different categories, but prevents duplicate SKUs within the same category.
Sparse Indexes
Sparse indexes only include documents that have the indexed field. Documents that don't contain the indexed field are skipped.
Creating a Sparse Index
db.customers.createIndex({ "premium_account_id": 1 }, { sparse: true })
In this example, only customers with a premium_account_id
field will be included in the index.
Benefits of Sparse Indexes
Sparse indexes are smaller than non-sparse indexes when the indexed field is missing from many documents. This can save storage space and improve write performance.
// These documents would be included in the sparse index
db.customers.insertMany([
{ name: "Alice", premium_account_id: "P123" },
{ name: "Bob", premium_account_id: "P456" }
])
// This document would NOT be included in the sparse index
db.customers.insertOne({ name: "Charlie" })
Partial Indexes
Partial indexes represent an evolution of sparse indexes with more flexibility. They only index the documents that meet a specified filter expression, allowing for even more granular control over which documents are indexed.
Creating a Partial Index
db.orders.createIndex(
{ orderDate: 1 },
{
partialFilterExpression: {
status: "active",
total: { $gt: 100 }
}
}
)
This index only includes documents where the status
field equals "active" and the total
field is greater than 100.
Partial vs. Sparse Indexes
Partial indexes offer more flexibility than sparse indexes:
// Sparse index only checks if the field exists
db.collection.createIndex({ field: 1 }, { sparse: true })
// Partial index can use any query criteria
db.collection.createIndex(
{ field: 1 },
{ partialFilterExpression: { field: { $exists: true, $gt: 10 } } }
)
TTL Indexes (Time-To-Live)
TTL indexes automatically remove documents from a collection after a specified amount of time. They're perfect for session data, temporary logs, or any data that should expire.
Creating a TTL Index
db.sessions.createIndex(
{ lastModified: 1 },
{ expireAfterSeconds: 3600 } // 1 hour
)
This index will cause documents to be deleted approximately 1 hour after the time specified in their lastModified
field.
Important TTL Constraints
- TTL indexes can only be created on fields containing date values.
- The TTL monitor runs every 60 seconds by default, so expirations may not be immediate.
- You can only specify the TTL property when creating the index.
// Insert a document with a date field
db.sessions.insertOne({
userId: "12345",
lastModified: new Date(),
data: { isLoggedIn: true }
})
// Document will be automatically removed after 1 hour
Hidden Indexes
Hidden indexes are maintained by MongoDB but not used by the query planner. This feature is useful for testing the impact of removing an index without actually dropping it.
Creating a Hidden Index
db.products.createIndex({ category: 1 }, { hidden: true })
Unhiding an Index
db.products.unhideIndex({ category: 1 })
Hidden indexes are particularly useful when you want to evaluate if an index is actually being used or if it's a good candidate for removal:
// Hide an index you suspect isn't needed
db.collection.collMod({
index: {
keyPattern: { field: 1 },
hidden: true
}
})
// Run your application and check if performance degrades
// If no issues, you can drop the index
// If problems occur, unhide it without rebuilding
db.collection.collMod({
index: {
keyPattern: { field: 1 },
hidden: false
}
})
Collation
Collation allows you to specify language-specific rules for string comparison, such as case insensitivity and accent sensitivity.
Creating an Index with Collation
db.users.createIndex(
{ lastName: 1 },
{
collation: {
locale: "en",
strength: 2 // Case-insensitive
}
}
)
Example Query Using Collation
For a query to use a collation-based index, it must specify the same collation:
db.users.find({ lastName: "smith" }).collation({
locale: "en",
strength: 2
})
// This will match "Smith", "SMITH", "smith", etc.
Combining Index Properties
Many index properties can be combined to create highly specialized indexes:
db.products.createIndex(
{ sku: 1 },
{
unique: true,
partialFilterExpression: { status: "active" },
collation: { locale: "en", strength: 2 }
}
)
This creates an index that:
- Enforces uniqueness on the
sku
field - Only indexes documents where
status
is "active" - Performs case-insensitive comparison of
sku
values
Practical Example: User Management System
Let's see how different index properties might be used in a user management system:
// 1. Unique index for user emails
db.users.createIndex(
{ email: 1 },
{ unique: true }
)
// 2. TTL index for password reset tokens
db.passwordResetTokens.createIndex(
{ createdAt: 1 },
{ expireAfterSeconds: 3600 } // Expires after 1 hour
)
// 3. Partial index for premium users
db.users.createIndex(
{ lastLogin: 1 },
{ partialFilterExpression: { accountType: "premium" } }
)
// 4. Case-insensitive search index
db.users.createIndex(
{ username: 1 },
{ collation: { locale: "en", strength: 2 } }
)
This system efficiently handles email uniqueness, automatically expires password reset tokens, optimizes queries specifically for premium users, and enables case-insensitive username searches.
Monitoring Index Properties
You can view all indexes and their properties using the getIndexes()
method:
db.collection.getIndexes()
This returns an array of documents describing each index, including all configured properties:
[
{
"v": 2,
"key": { "_id": 1 },
"name": "_id_",
"ns": "test.collection"
},
{
"v": 2,
"key": { "email": 1 },
"name": "email_1",
"unique": true,
"ns": "test.collection"
},
{
"v": 2,
"key": { "createdAt": 1 },
"name": "createdAt_1",
"expireAfterSeconds": 3600,
"ns": "test.collection"
}
]
Summary
MongoDB index properties provide powerful ways to customize how your indexes work:
- Unique indexes prevent duplicate values
- Sparse indexes only index documents containing the indexed field
- Partial indexes only index documents matching specific criteria
- TTL indexes automatically remove documents after a specified time
- Hidden indexes are maintained but not used by the query planner
- Collation allows language-specific string comparisons
By choosing the right index properties, you can optimize performance, enforce data integrity, and implement advanced features like automatic document expiration.
Additional Resources
- MongoDB Official Documentation on Index Properties
- MongoDB University Course M201: MongoDB Performance
Exercises
- Create a unique index on a
productCode
field in aproducts
collection. - Create a TTL index that expires documents in a
sessions
collection after 30 minutes. - Create a partial index that only indexes customers with a
premiumMember
field set totrue
. - Create a case-insensitive index on a
tags
field using collation. - Create a compound index with mixed properties: make it unique on
{email: 1, organizationId: 1}
but only for documents wherestatus
is "active".
Understanding and correctly applying these index properties will help you build more efficient and robust MongoDB applications.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)