nodejs wait until all MongoDB calls in loop finish
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When MongoDB calls are made inside a loop in Node.js, the common mistake is to start all the async work and then immediately continue as if it has already finished. The fix is not "wait for the loop." It is to collect or await the promises created inside the loop. Once you do that, the code becomes predictable and much easier to reason about.
The Wrong Pattern
This pattern starts database operations but does not wait for them:
forEach does not understand await in the way many people expect. The "done" line runs immediately, before the queries finish.
Use Promise.all for Parallel Work
If the MongoDB operations are independent and you want them to run concurrently, map each item to a promise and wait for all of them together.
The important detail is that ids.map(...) returns an array of promises. Promise.all(...) waits until every promise resolves or until one rejects.
Handle Errors Deliberately
Promise.all fails fast. If one MongoDB call rejects, the entire await Promise.all(...) throws. That is often correct, but not always.
If you want to collect both successes and failures, use Promise.allSettled:
This is useful when one bad document ID should not discard all other results.
Use for...of for Sequential Work
Sometimes you do not want parallel queries. Maybe each query depends on the previous one, or maybe you need to limit database pressure. In that case, use for...of with await.
This runs one query at a time. It is slower than parallel execution, but the control flow is explicit and safe.
Avoid Opening a New Connection in Every Iteration
Another common mistake is connecting to MongoDB inside the loop. That creates unnecessary overhead and can exhaust connection limits.
Bad pattern:
Good pattern:
- create one client
- connect once
- reuse the collection handle
- close the client when all work is complete
The MongoDB driver is built for connection reuse. Use it that way.
Prefer Bulk Operations When Possible
If the loop is doing many inserts, updates, or deletes, waiting for all promises may still be the wrong design. MongoDB often provides a bulk operation that is more efficient and easier to reason about.
For example, instead of many separate inserts:
Or instead of fetching one document at a time, fetch many at once when the query shape allows it:
That is often better than launching dozens or hundreds of findOne calls.
Concurrency Limits Matter
Blindly firing thousands of MongoDB queries with Promise.all can overwhelm the application or the database. If the input list is large, limit concurrency with a queue or a utility library.
A simple chunking approach:
This keeps concurrency under control without making the whole workload fully sequential.
Choose the Pattern Based on Intent
The right answer depends on the workload:
- independent queries:
Promise.all - independent queries with partial failure handling:
Promise.allSettled - order-dependent or rate-limited queries:
for...ofwithawait - many similar write operations: use MongoDB bulk APIs
The mistake is not asynchronous programming itself. The mistake is using a loop construct that does not match the async semantics you need.
Common Pitfalls
- Using
forEachwithasyncand expecting the outer code to wait automatically. - Opening and closing a MongoDB client inside every iteration instead of reusing one connection.
- Using
Promise.allfor a huge list and overwhelming the database with uncontrolled concurrency. - Launching many single-document operations when one bulk query or bulk write would be more efficient.
- Forgetting that
Promise.allrejects as soon as one promise fails.
Summary
- To wait for MongoDB calls in a loop, wait for the promises created by the loop, not the loop construct itself.
- Use
Promise.allfor parallel independent operations. - Use
Promise.allSettledwhen you need success and failure details for every operation. - Use
for...ofwithawaitfor sequential or rate-limited execution. - Reuse the MongoDB client and prefer bulk operations when the database can do the work more efficiently.

