In my mongoDB database I have a Posts
model, which contains array of references to a Comments
model.
For one of the get requests in my Express application I have to respond with an array of all the Posts in the database with each Post containing an array of all the comments it has
The method I chose to do this is, get all the Posts using find, which returned an array of all the posts, each post containing array of references to the comments it has, according to my model.
To resolve those references I chose the populate method provided by mongoose, which returns the actual objects from the database against the references it contains, which was pretty straightforward for a post
await post.populate("comments").execPopulate();
here post is the single post instance and after this operation the post instance contains all its comment references resolved into comment objects
but to do that individually for every post I tried two methods, where allPosts
is the array of all posts I get after the find query
- using the above execPopulate operation, create an array of all promises, without regard for whether they were resolved, then using
Promise.all()
perform further operation after all were resolved
let promiseArray = allPosts.map( (post) => {
post.populate("comments").execPopulate();
});
Promise.all(promiseArray).then((posts) => {
// this map is another extra irrelevant operation I performed to
// format the response array in a particular way, where
// I had to remove extra fields in both the posts array
// as well as the populated comments array
let responseArray = posts.map((post) => {
return {
comments: filterComments(post.comments),
_id: post._id,
title: post.title,
commentcount: countComments(post.comments),
};
});
return res.send(responseArray);
});
- the other method I tried was to set up a while loop, where I wait for every post to be resolved individually in every iteration, then push the resolved and formatted post object in an array(reponse array) and after completion send the response array
let responseArray = [];
let length = allPosts.length;
let counter = allPosts.length;
while(counter) {
// get the first post because counter is reverse
let post = allPosts[length - counter]
// the population operation where every post array
// is populated with its comments
await post.populate('comments').execPopulate();
// push the filtered object to another array
responseArray.push({
comments : filterComments(post.comments),
_id : post._id,
title : post.title,
commentcount : countComments(post.comments),
})
counter --;
}
return res.send(responseArray);
the application took thrice the time to respond to the same set of data of around 150 or so posts when using while loop to resolve individual promises, and was faster when I stored all promises in array and then resolved them in Promise.all()
, I don't know the JS event loop very much in detail so wanted to know if there's something causing this
TL;DR :
I have a list of async operations to perform on every element in an array, I tried:
iterate through the array storing all the unresolved promises in an array, then doing further operation after using
Promise.all()
on the array of promisesiterate through the array using while loop, performing the async operation for every element on every iteration
the while loop takes almost thrice the time, resolution on Promise.all()
takes