BackendMongoDBDatabasePerformanceBackendNode.js

MongoDB Performance Optimization: 10 Expert Tips

From indexing strategies to aggregation pipelines — practical MongoDB optimization techniques backed by real-world experience.

Abdur Razzak

Abdur Razzak

Full-Stack Web Developer

March 8, 2024 9 min read

Index Everything You Query On

The single biggest MongoDB performance win is proper indexing. Without an index, MongoDB does a full collection scan — reading every document to find matches. For a collection with 1 million documents, a full scan takes seconds; an indexed query takes milliseconds. Create indexes on every field you filter by (find()), sort by, and join on. Use db.collection.explain('executionStats') to verify queries are using indexes.

Use Compound Indexes Strategically

Compound indexes cover multiple fields. Create them following the ESR rule: Equality fields first, Sort fields second, Range fields last. A compound index on { userId: 1, createdAt: -1 } serves queries that filter by userId and sort by newest first — a common pattern in social feeds and activity logs. One compound index often replaces two or three single-field indexes.

Project Only the Fields You Need

Fetching entire documents when you only need 3 fields wastes bandwidth and memory. Use MongoDB projection: find({}, { title: 1, slug: 1, publishedAt: 1 }). If your index covers all the projected fields, MongoDB can answer the query from the index alone without reading the full documents — a covered query, which is the fastest possible query.

Aggregate Instead of Multiple Queries

MongoDB's aggregation pipeline is powerful enough to replace most scenarios where you would do multiple queries and combine results in application code. $lookup (left join), $group (group by), $unwind (flatten arrays), and $facet (multiple aggregations in one pass) let you do complex data transformations server-side. This reduces round trips and lets the database use its query optimizer.

Pagination with Cursor-Based Approach

Skip-based pagination (skip(100).limit(20)) gets slower as the offset grows because MongoDB still reads and discards all the skipped documents. For large collections, use cursor-based pagination: store the _id or createdAt of the last document on each page, and query with find({ _id: { $gt: lastId } }).limit(20). This is O(log n) instead of O(n) and works perfectly for infinite scroll.

Enable Compression and Connection Pooling

Configure Mongoose's connection pool to match your server's expected concurrency — typically 10-50 connections. Connection pooling eliminates the overhead of establishing a new database connection for every request. Enable snappy or zlib compression in your MongoDB URI to reduce data transfer between your application server and database. These settings alone can improve throughput by 20-30%.

Share this article

All posts
#MongoDB#Database#Performance#Backend#Node.js
Abdur Razzak — Full Stack Web Developer

Free Consultation

Got a Project Idea? Let's Talk.