Reputation: 313
ignore the syntax error.i need to do perform some thing with i value inside aggregate and need to update it,but when i execute the below code, the for loop is not waiting to finish till update.it iterate i value very fast and the aggregate skips every i value. am new to javascript so,incase if the question is silly sorry for that too
model.countDocuments((err,count)=>{
for(i=value;i<count;i++){
console.log(i)
model.aggregate({[//some update function]})
.then((res)=>model.update({field:something},{$set:res.value}}))
})
Upvotes: 0
Views: 99
Reputation: 4737
You can use Promise.all
to still have most of your work done concurrently, and still have your results when they are all done running, in the same order you started them. Here's a fully working example that somewhat resembles your problem.
// Generate a random value between 250 and 500. Used for the delay to setTimeout
// to mimic "long running" operations.
const delay = () => Math.floor(Math.random()*(500 - 250 + 1))+250;
// This represents your model.aggregate function. Takes an input of a number for
// the sake of correlation in this example. Always resolves a string with the
// intention of passing it into the next "then."
const aggregate = (i) => {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve(`[${i}]: aggregated`) }, delay());
});
};
// This represents your model.update function. Takes a number for the sake of
// correlation and the result from the "aggregate" function.
const update = (i, res) => {
// result from aggregate
console.log(`[${i}]: ${res}`);
return new Promise((resolve, reject) => {
setTimeout(() => { resolve(`[${i}]: updated`) }, delay());
});
};
// A helper to generate an array of numbers. Just a "fancier" alternative to
// "for i=value; i<count; i++"
const range = (i) => [...Array(i).keys()]
// An arbitrary number for the amount of work to run in this example. This
// represents "count" in your example.
const count = 10;
// This is the equivalent of what would be your for loop's body. Executes "count"
// amount of work and stores all the the promises into an array. Even though we
// have a list of promises in the array, this is non-blocking and the program will
// continue until we wait for them to all resolve later.
const res = range(count).map((i) => {
console.log(`[${i}]: starting`);
return aggregate(i).then((res) => update(i, res));
});
// Wait for all promises to resolve and print the final results. At this
// exact moment, some be still running and some may have completed.
// Call then will let you get the results of all the work when they are
// are all resolved.
//
// The block in "catch" will be called when any one of them "rejects" or
// throws an exception.
Promise.all(res).
then((vals) => { for (const val of vals) { console.log(val) } }).
catch((err) => { console.error(err) });
Here's an example output:
[0]: starting
[1]: starting
[2]: starting
[3]: starting
[4]: starting
[5]: starting
[6]: starting
[7]: starting
[8]: starting
[9]: starting
[6]: [6]: aggregated
[2]: [2]: aggregated
[4]: [4]: aggregated
[7]: [7]: aggregated
[9]: [9]: aggregated
[3]: [3]: aggregated
[0]: [0]: aggregated
[1]: [1]: aggregated
[8]: [8]: aggregated
[5]: [5]: aggregated
[0]: updated
[1]: updated
[2]: updated
[3]: updated
[4]: updated
[5]: updated
[6]: updated
[7]: updated
[8]: updated
[9]: updated
Notice that the final outputs are in the same order as how they are started (0 through 9). However, the "aggregate" and "update" are still run asynchronously.
The point of this is that you don't need to wait for the first "aggregate then update" call to finish to run the next "aggregate then update," then the next "aggregate then update" after that and so on. Pretty much throwing "asynchronicity" out the window. Using async/await definitely has its place (and I use them plenty), but I'd argue that this is not a great place to use it.
Upvotes: 1
Reputation: 478
Try using async/await functionality
Change your code to this
model.countDocuments(async (err,count)=>{
for(i=value;i<count;i++){
console.log(i);
let res = await model.aggregate({[/*some update function]*/});
model.update({field:something},{$set:res.value}});
}
)
Using the await keyword will make the code wait until the promise is returned and continue on the next statement.
To use the 'await' keyword, the enclosing function needs to declare itself as an 'async' function
Upvotes: 1