1

I am aware that I used "wait" and "asyncronous" word in the same sentense which doesn't make sense. But I would like to know if someone can suggest me a solution to my problem.

I have for loop that runs on an array of docs returned by mongodb. Now, depending on some logic I need to remove certain document. Only after I am finished removing the docs, I can call my next method. Looks something like following:

mymongodbconnection.find({}).toArray(function(err, documents) {
if (!err && documents.length !== 0) {
  documents.forEach(function(document) {

      if( someCheckPerformed(document)){
        console.log('keeping');
      }else{
        console.log('removing');
mymongodbconnection.remove({_id:document._id},fun(err,result){});
      }
  });

 notifyAdminAboutChange();
} else {
  logger.warn('No existing UA docs to filter');
}
});

Now, as you can see, I need to call notifyAdminAboutChange(); only after for loop has finished iterating over all the docs and has removed docs that needs to be removed.

My questions:

  1. Can I block the for loop execution to wait for removal to finish?
  2. If 1 is not possible then how do I achieve this use case?
java_doctor_101
  • 3,287
  • 4
  • 46
  • 78
  • The answer is probably to use promises and promise-do-whilst... but what is mongodBCollectionInstance? Also you may need to use a writeConcern with your remove function for Mongo – vicatcu Jun 30 '17 at 00:58
  • You can't make Javascript "wait". Instead, you have to either change the structure of your loop to sequence your async operations or you have to start them all and track when they are all done with something like `Promise.all()`. Some related answers: [How to synchronize a sequence of promises?](https://stackoverflow.com/questions/29880715/how-to-synchronize-a-sequence-of-promises/29906506#29906506) and [Asynchronous function inside a javascript for loop](https://stackoverflow.com/questions/23771371/asynchronous-function-inside-a-javascript-for-loop/23771475#23771475) – jfriend00 Jun 30 '17 at 00:59

2 Answers2

0

I don't know of any JS slights of hand to easily shim into your existing structure, but if you rearrange a little and keep your mind open to a recursive solution, you might achieve your desired result:

coll.find({}).toArray((err, docs)=> {
    (function checkDoc(i){
        if(i >= docs.length) return;
        else if(pred(docs[i])) checkDoc(i + 1);
        else coll.remove({_id: docs[i]._id}, _=> checkDoc(i + 1));
    })(0);
})

This way, the documents are checked in order, and the next document is only processed when the current one is completely done being processed.

demo

wbadart
  • 2,583
  • 1
  • 13
  • 27
0

Use promises - create one for each doc to remove, and then wait for them all to resolve (using Promise.all) before calling your function.

mongodBCollectionInstance.find({}).toArray(function(err, documents) {
  if (!err && documents.length !== 0) {
    var promises = [];

    documents.forEach(function(document) {
      if( someCheckPerformed(document)){
        console.log('keeping');
      }else{
        console.log('removing');
        promises.push(new Promise(function (fulfill, reject){
          mongodBCollectionInstance.remove(
            {_id:document._id},
            function (err, result) {
              fulfill();
            });
        }))
      }
    });
    Promise.all(promises).then(function () {
      notifyAdminAboutChange();
    });
  } else {
    logger.warn('No existing UA docs to filter');
  }
});
Greg
  • 9,963
  • 5
  • 43
  • 46
  • Hey @Greg, thanks for helping me out. Quick question: If I call fulfill on some promises and reject on others , does Promises.all will still be called Or does all the promised needs to be fullfilled for Promises.all to be called? – java_doctor_101 Jun 30 '17 at 15:32