1

I have the same problem as this question but cant get the solution to work. I'm trying to write a nodejs script that will first check for a cached value in mongo but if it doesnt exist then go off and calculate it. The problem is that the findOne() callback doesnt get the original value of the loop variable so the callback cant correctly calculate and store the value. (I've omitted the actual fetching, storing and returning to focus on the actual issue I'm having). Whatever I do I cant get the original value to feed into the callback.

for (var d=start_date; d<now; d.setHours(d.getHours()+1)) {
          (function(key) {
          console.log('caller='+key)

          db.collection('avgs').findOne( { date:  key.toISOString() },function (err,data) {
           console.log('callback='+key);
           if (data) { //return data }
           else { // compute average for given date , insert into database and return value }
          });
          })(d);
        };

The console log shows this

caller=Tue Mar 25 2014 00:00:00 GMT+1030 (CST)
caller=Tue Mar 25 2014 01:00:00 GMT+1030 (CST)
caller=Tue Mar 25 2014 02:00:00 GMT+1030 (CST)
caller=Tue Mar 25 2014 03:00:00 GMT+1030 (CST)
callback=Wed Mar 26 2014 14:00:00 GMT+1030 (CST)
callback=Wed Mar 26 2014 14:00:00 GMT+1030 (CST)
callback=Wed Mar 26 2014 14:00:00 GMT+1030 (CST)
callback=Wed Mar 26 2014 14:00:00 GMT+1030 (CST)
Community
  • 1
  • 1
rw950431
  • 115
  • 1
  • 9

2 Answers2

3

I'm guessing your problem is that you're sending the value d in to the wrapped function, and inside that function modifying that value in some way. Since d is a reference to your loop iterator, modifying it modifies your loop. The solution would be to create a copy of the object inside your function:

    for (var d=start_date; d<now; d.setHours(d.getHours()+1)) {
      (function(_key) {
      // Make a copy of the object you passed in, so that modifying it
      // won't screw up your loop
      var key = new Date(_key);
      console.log('caller='+key)

      db.collection('avgs').findOne( { date:  key.toISOString() },function (err,data) {
       console.log('callback='+key);
       if (data) { //return data }
       else { // compute average for given date , insert into database and return value }
      });
      })(d);
    };
sgress454
  • 24,870
  • 4
  • 74
  • 92
0

Using the technique of creating a copy of the loop variable I found I was also able to use bind() to get the same result. Same result but the code reads better to my eye.

db.collection('avgs').findOne( { date:  key.toISOString() },found.bind(this,new Date(d));

function found(key,err,data) {
 console.log('callback='+key);
 if (data) { //return data }
 else { // compute average for given date , insert into database and return
}; 

It appears that javascript usually passes a reference rather than a value although not always

Community
  • 1
  • 1
rw950431
  • 115
  • 1
  • 9