Callback after forEach loop?

6,913 views
Skip to first unread message

Eva Schindling

unread,
Dec 8, 2011, 6:36:15 PM12/8/11
to mongoo...@googlegroups.com
I am querying an array of documents and try to remove several of their embedded documents, before passing on the documents-array. I use two forEach loops in order to go through all the main documents and through each of their embedded document arrays. It seems that process is slower than the arrival of the data-handoff function call (sendOutData), as not all the embedded documents - that should get removed - get removed. 

Is there a way to trigger the data-handoff function like a callback once the forEach loops are done? I tried with the index-variable of the forEach-loop, but ran in to problems, as not all main documents have an array of embedded documents (rewrites). Also it seemed the forEach callbacks didn't arrive in their original order.

db.headline.find({'date': x }, function (err, docs) {
        if(err) { util.log(err.message); }
        if(docs) {
            docs.forEach( function(d) {
               d.rewrites.forEach( function (r) {
                   if(r.blocked) { d.rewrites.id(r._id).remove();  }
               });
            });
            sendOutData(docs);          // hand off docs  !! apparently this happens too early,
                                        //                   not all the removals haven't happened yet
        }
    });


All seems to work fine when i test it on my local machine, but once it is uploaded to the remote server, a lag in the execution seems to introduce mistakes.

Any help would be appreciated!
Even if it entails completely changing all my code, because it could be done so much easier! :)

Thanks,
Eva

Gabriel Petrovay

unread,
Dec 9, 2011, 7:55:22 AM12/9/11
to mongoo...@googlegroups.com
Hi Eva,

This thread addresses a similar problem with yours (on a different topic though, but the "async" part is the key, I guess, in both topics):

The 2nd answer uses the length variable. That means, putting your sendOutData(docs); inside the forEach loop guarded by an if that checks whether length reached the size of your docs array. And each function (r) iteration start with a length++

So this might do the job for you even though I am not sure about possible race conditions for the length variable. Any thought on this anyone?


Gabriel



--
http://mongoosejs.com
http://github.com/learnboost/mongoose
You received this message because you are subscribed to the Google
Groups "Mongoose Node.JS ORM" group.
To post to this group, send email to mongoo...@googlegroups.com
To unsubscribe from this group, send email to
mongoose-orm...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/mongoose-orm?hl=en



--
MSc Gabriel Petrovay
Mobile: +41(0)787978034

Thomas Blobaum

unread,
Dec 9, 2011, 8:52:45 AM12/9/11
to mongoo...@googlegroups.com
This is a pretty common problem. This video might help you as well. http://vimeo.com/32851269

Aaron Heckmann

unread,
Dec 9, 2011, 9:11:41 AM12/9/11
to mongoo...@googlegroups.com
Short answer: use a reverse loop if manipulating the array within the loop:

var i = d.rewrites.length;
while (i--) {
  if (blah) {
     d.rewrites.splice(i, 1)
  }
}

Long answer:

Manipulating an array within a forEach causes the same problems splicing an array within a forward loop cause, all elements following the index of the splice shift one position to the left:

var arr = [3,4,5,6,7]
for (var i = 0, len = arr.length; i < len; ++i) {
  console.log(i);
  arr.splice(i, 1);
}

After this, arr holds [4,6]. Breaking it down a bit:

var arr = [3,4,5,6,7]
arr.splice(0, 1) // arr is [4,5,6,7]
arr.splice(1, 1) // arr is [4,6,7]
arr.splice(2, 1) // arr is [4,6]
arr.splice(3, 1) // no change
arr.splice(4, 1) // no change

Not the intention. Instead, start the index from the end and iterate to the beginning and it will behave as desired.

var arr = [3,4,5,6,7]
arr.splice(4, 1) // arr is [3,4,5,6]
arr.splice(3, 1) // arr is [3,4,5]
arr.splice(2, 1) // arr is [3,4]
arr.splice(1, 1) // [3]
arr.splice(0, 1) // []

Eva Schindling

unread,
Dec 9, 2011, 12:19:12 PM12/9/11
to mongoo...@googlegroups.com
Alright, i think this did the trick!
Skipping forEach for a while-loop, and looping in reverse order.

Thanks!!


var d = docs.length;
while(d--) {
var doc = docs[d];
var r = doc.rewrites.length;
while(r--) {
if(doc.rewrites[r].blocked) {
doc.rewrites.splice(r,1);
}
}
if(d==0) {
sendOutData(docs);
}
}

Gabriel Petrovay

unread,
Dec 11, 2011, 2:49:50 PM12/11/11
to mongoo...@googlegroups.com
Just came across this video: http://vimeo.com/32851269

Alex Young gives this as his first example in his presentation (minute 3:00)

}

--
http://mongoosejs.com
http://github.com/learnboost/mongoose
You received this message because you are subscribed to the Google
Groups "Mongoose Node.JS ORM" group.
To post to this group, send email to mongoo...@googlegroups.com
To unsubscribe from this group, send email to
mongoose-orm...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/mongoose-orm?hl=en
Reply all
Reply to author
Forward
0 new messages