Indexing
Choosing Indexes
Which queries deserve an index, which indexes to drop, and the write cost of getting greedy.
Index the hot queries, not the schema. List the filters and sorts that run on the request path. One compound index per that shape beats a pile of single-field indexes. Then stop. Every extra index slows writes and fights for RAM.
- Do.
{ userId: 1, createdAt: -1 }for Rahul's order history. Unique{ email: 1 }.{ "items.name": 1 }only if you query that path for real. - Don't. An index per field on
users.{ isActive: 1 }alone. A text index for exact SKU. Duplicating{ city: 1 }when{ city: 1, name: 1, age: 1 }already has that prefix. - Partial.
{ isActive: true }inpartialFilterExpressionso the index only holds the slice you query — smaller, still unique-capable. - Covered queries (next module): if filter + projection fields all sit in the index, the server can skip fetching the document. Do not add ten keys 'to cover' a rare report.
db.orders.aggregate([{ $indexStats: {} }])$indexStats (ops count) is how you find indexes nobody uses — then dropIndex. A collection with twenty indexes on a write-heavy orders stream is a modelling or API smell. Build indexes in production with a rolling build on a replica set (Production module); do not pretend createIndex is free on a hot primary with a huge collection.
Interview question
How do you decide which indexes to create and which to drop?
Start from the hot queries — equality, sort, range — and build one compound index per shape using ESR. Skip low-selectivity standalone fields. Each index costs writes and RAM, so I look at $indexStats and drop unused ones. I do not index every field, and I do not keep two indexes that share the same left prefix unless a second query cannot use the first.