What is an index in MongoDB, and why use one?
A sorted structure (a B-tree) of field values with pointers to the documents. Without one, a query reads every document (a collection scan,
COLLSCAN); with one, it walks only the matching keys (IXSCAN). An index also returns results already sorted. The cost: every insert, update and delete must update each index, and indexes take RAM and disk. Every collection has an index on_id.How do you create an index?
createIndexwith the fields and a direction,1ascending or-1descending, plus options such asunique,name,partialFilterExpressionorexpireAfterSeconds. The default name joins fields and directions, likeemail_1. In the shell it isdb.users.createIndex({ email: 1 }, { unique: true }).Node.jsconst { MongoClient } = require('mongodb'); const client = new MongoClient('mongodb://localhost:27017'); async function main() { const users = client.db('shop').collection('users'); await users.createIndex({ email: 1 }, { unique: true }); await users.createIndex({ city: 1, age: -1 }); const indexes = await users.indexes(); console.log(indexes.map((i) => i.name)); } main().finally(() => client.close());Can two documents without the field share a unique index?
Node.jsconst { MongoClient } = require('mongodb'); const client = new MongoClient('mongodb://localhost:27017'); async function main() { const users = client.db('shop').collection('users'); await users.createIndex({ email: 1 }, { unique: true }); await users.insertOne({ name: 'Asha' }); try { await users.insertOne({ name: 'Ravi' }); console.log('inserted'); } catch (err) { console.log('error', err.code); } } main().finally(() => client.close());It prints
error 11000. A unique index stores a missing field asnull, so a second document without an email collides with the first. To make the field optional but unique when present, use a partial index:createIndex({ email: 1 }, { unique: true, partialFilterExpression: { email: { $exists: true } } }).How do you choose the field order in a compound index?
Follow the ESR rule: Equality fields first, then Sort fields, then Range fields. For
find({ status: 'paid', total: { $gt: 100 } }).sort({ date: -1 })the index is{ status: 1, date: -1, total: 1 }; puttingtotalbeforedatewould force an in-memory sort. A compound index also serves its prefixes:{ a: 1, b: 1, c: 1 }helps queries ona, onaandb, and on all three, but not onbalone.What is a multikey index?
An index on an array field. MongoDB makes it multikey automatically and stores one index key per element, so
{ tags: 1 }servesfind({ tags: 'node' }). Limits: in a compound multikey index, each document may have at most one indexed field that is an array; a multikey index cannot be a shard key; and long arrays mean many keys per document, which slows writes.What is a text index, and what are its limits?
A text index tokenizes and stems string fields so you can search words with
$textand sort by relevance. A collection can have only one text index (it may cover several fields), and it has no prefix, fuzzy or autocomplete matching. On MongoDB Atlas, Atlas Search (built on Lucene) is the usual choice for search features.db.articles.createIndex({ title: 'text', body: 'text' }) db.articles.find({ $text: { $search: 'index tuning' } }, { score: { $meta: 'textScore' } }) .sort({ score: { $meta: 'textScore' } })What is a TTL index?
A single-field index on a date field with
expireAfterSeconds: a background task deletes each document once that many seconds have passed since its date. It suits sessions, one-time codes and temporary logs. The task runs every 60 seconds, so documents can outlive their expiry a little, and documents whose field is not a date never expire.db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 }) // expire at a time stored in each document db.tokens.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 })What is the difference between a partial and a sparse index?
A sparse index skips documents that lack the field. A partial index (3.2+) skips documents that do not match a filter you give, such as
{ status: 'active' }; it can do everything sparse does and is the recommended choice. Both are smaller and cheaper to maintain, but the planner uses one only when the query's filter guarantees the index holds every match, so a query withoutstatus: 'active'ignores that partial index.What is a covered query?
A query answered from the index alone: every field in the filter and the projection is in the index, so MongoDB never fetches the documents.
explainshows noFETCHstage andtotalDocsExamined: 0. Exclude_idunless it is in the index; a field that holds an array cannot be covered.db.users.createIndex({ email: 1, name: 1 }) db.users.find({ email: 'asha@example.com' }, { _id: 0, email: 1, name: 1 })How do you check whether a query uses an index?
Run it with
explain('executionStats'). In the winning plan,IXSCANmeans an index scan andCOLLSCANa full scan. Then comparenReturned,totalKeysExaminedandtotalDocsExamined: in a good plan all three are close. Thousands of documents examined to return ten means a missing or badly ordered index. The SQL counterpart is EXPLAIN QUERY PLAN.db.orders.find({ status: 'paid' }).sort({ date: -1 }).explain('executionStats')Can a collection have too many indexes?
Yes. Each index adds work to every insert and to every update of its fields, takes disk space, and competes for RAM with your data. The hard limit is 64 indexes per collection, but writes suffer long before that. Find unused ones with the
$indexStatsstage, and hide an index (hideIndex, 4.4+) to test removing it before you drop it.Does the direction of fields in a compound index matter?
For a single-field index, no: MongoDB can walk it either way. For a compound index used to sort, yes:
{ date: 1, score: -1 }supportssort({ date: 1, score: -1 })and its exact reverse,sort({ date: -1, score: 1 }), but notsort({ date: 1, score: 1 }), which needs an in-memory sort.
MongoDB Indexing Interview Questions
How indexes speed up reads: single-field, compound, multikey, unique, partial and TTL indexes, the ESR rule and covered queries.