Create single, compound, and text indexes. Use explain() to analyze query plans.
Without an index, MongoDB scans every document to find matches. With an index, it jumps directly to matching documents. On a million-document collection, the difference is seconds vs milliseconds.
// Single-field index
db.users.createIndex({ email: 1 })
// Unique index
db.users.createIndex({ email: 1 }, { unique: true })
// Compound index
db.products.createIndex({ category: 1, price: -1 })
// Text index for full-text search
db.products.createIndex({ name: 'text', description: 'text' })
// Sparse index (only index documents that have the field)
db.users.createIndex({ phone: 1 }, { sparse: true })
// List indexes
db.users.getIndexes()
// Drop an index
db.users.dropIndex('email_1')// Without explain
db.users.find({ email: '[email protected]' })
// With explain
db.users.find({ email: '[email protected]' }).explain('executionStats')
// Key fields to check:
// executionStats.nReturned → documents returned
// executionStats.totalDocsExamined → documents scanned
// If nReturned << totalDocsExamined → you need an index
// executionStats.executionTimeMillis → time in msstatus where 90% of documents have status='active' is nearly useless — it still scans most documents. Index fields with high cardinality (many unique values): email, username, ID.{category:1, price:-1} supports queries on category alone or category+price.explain('executionStats') shows docs scanned vs returned. High ratio = missing index.$text: { $search: 'keyword' } full-text search.