How to Optimize MongoDB Queries With Indexes
Slow queries kill UX. Here is how to optimize MongoDB queries with indexes.
How to Optimize MongoDB Queries With Indexes
Slow queries kill UX. Here is how to optimize MongoDB queries with indexes.
Step 1: Find Slow Queries
Use the MongoDB profiler or your APM to find slow queries. Look for queries that scan many documents (high totalDocsExamined).
Step 2: Run explain()
User.find({ email }).explain('executionStats');
Look at:
executionStats.totalDocsExamined: should be small (just the matching docs).executionStats.totalKeysExamined: should be small (just the index entries scanned).winningPlan.stage: COLLSCAN means collection scan (bad); IXSCAN means index scan (good).
Step 3: Add an Index for the Query
userSchema.index({ email: 1 }, { unique: true });
Re-run explain(). totalDocsExamined should drop.
Step 4: Use Compound Indexes for Multi-Field Queries
connectionRequestSchema.index({ fromUserId: 1, toUserId: 1 }, { unique: true });
messageSchema.index({ connectionId: 1, createdAt: -1 });
Order by the ESR rule: equality, sort, range.
Step 5: Use .lean() for Read-Only Queries
const users = await User.find().lean();
Skips hydrating full Mongoose documents. Faster and uses less memory.
Step 6: Select Only the Fields You Need
const users = await User.find().select('firstName email').lean();
Reduces payload and memory. If the index covers the fields, it is a covered query (even faster).
Step 7: Paginate With Cursor Instead of Skip
Skip is slow for large offsets (MongoDB still scans skipped docs). Use cursor-based pagination:
const messages = await Message.find({ connectionId, createdAt: { $lt: cursor } })
.sort({ createdAt: -1 })
.limit(20);
Step 8: Avoid $where and $regex on Unindexed Fields
$where runs JavaScript (slow). $regex on an unindexed field scans the whole collection. Use a text index for search, or index the field if you need regex.
Step 9: Use countDocuments Carefully
countDocuments can be slow without an index. If you only need to know if documents exist, use findOne and check for null:
const exists = await User.findOne({ email }).select('_id');
Step 10: Monitor in Production
Watch slow queries with the profiler or APM. Add indexes as query patterns emerge. Do not assume your indexes are perfect; data and queries evolve.
The Takeaway
Optimize MongoDB queries: find slow queries with the profiler, run explain(), add indexes, use compound indexes for multi-field queries, use .lean() for read-only, select only needed fields, paginate with cursor, avoid $where and unindexed $regex, use findOne for existence checks, and monitor in production.
Run explain('executionStats'). If totalDocsExamined equals the collection size, add an index for the query fields. Use compound indexes for multi-field queries. Use .lean() and select only needed fields. Paginate with cursor instead of skip.
Look at executionStats.totalDocsExamined (should be small), executionStats.totalKeysExamined (should be small), and winningPlan.stage (COLLSCAN is bad, IXSCAN is good). If totalDocsExamined equals the collection size, the index is not used.
MongoDB still scans the skipped documents before returning the ones you want. For large offsets, use cursor-based pagination: find documents where createdAt is less than the last cursor. Faster because MongoDB uses an index.
It skips hydrating full Mongoose documents and returns plain JS objects. Faster and uses less memory. Use for read-only queries where you only need to send JSON. Do not use it if you need to call instance methods or save the document.
$where runs JavaScript in the database (slow). $regex on an unindexed field scans the whole collection. Use a text index for search, or index the field if you need regex. Both operators are common causes of slow queries.
Ready to master Node.js completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master Node.js
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

