2

I'm using mongo and need to do an async call for each item inside of a loop. I'd like to execute another command once all of the promises inside of the loop have completed, but so far the promises in the loop seem to be completing after the code that's in the then that's after the loop.

Essentially i'd like the order to be

Loop promises then other code

instead of what it is now which is

other code Loop promises

MongoClient.connect(connecturl)
.then((client) => {
  databases.forEach((val) => {
    val.collection.forEach((valcol) => {
      client.db(val.databasename).stats() //(This is the async call)
      .then((stats) => {
        //Do stuff here with the stats of each collection
      })
    })
  })
})
.then(() => {
  //Do this stuff after everything is finished above this line
})
.catch((error) => {
}

Any assistance would be appreciated on this one.

1 Answer 1

4

Assuming the things you are using .forEach() on are iterables (arrays or something like that), you can use async/await to serialize a for/of loop:

    MongoClient.connect(connecturl).then(async (client) => {
        for (let db of databases) {
            for (let valcol of db.collection) {
                let stats = await client.db(db.databasename).stats();
                // Do stuff here with the stats of each collection
            }
        }
    }).then(() => {
        // Do this stuff after everything is finished above this line
    }).catch((error) => {
        // process error
    })

If you wanted to stick with your .forEach() loops, you could make it all work if you did things in parallel and used Promise.all() to know when it's all done:

MongoClient.connect(connecturl).then((client) => {
    let promises = [];
    databases.forEach((val) => {
        val.collection.forEach((valcol) => {
            let p = client.db(val.databasename).stats().then((stats) => {
                // Do stuff here with the stats of each collection
            });
            promises.push(p);
        }); 
    });
    return Promise.all(promises);
}).then(() => {
    // Do this stuff after everything is finished above this line
}).catch((error) => {
    // process error here
});
Sign up to request clarification or add additional context in comments.

6 Comments

Top level await wasn't ready yet, then callback needs to be marked as async.
@Xlee - You're right. I added an async to the first .then() handler and removed the outer async wrapper function.
I'm using your forEach solution where you push the promises to the array and it seems to work exactly how I want to! I think it screwed something up though where i'm grabbing the database stats with "stats" rather than the collection stats.
@Milos The reason yours doesn't work is your first then doesn't return a Promise, thus treated as a synchronous call. I like the solution using Promise.all, since it parallelizes your async tasks. You can also use reduce function to achieve sequential async tasks though.
@Xlee by the first do you mean the mongoconnect needs to return a promise or am i reading into your comment wrong? If you could explain it a little further i'd appreciate it very much. Thanks.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.