2

I have this issue with querying mongodb asynchronously from node.js. Here is my code

var values = [];
var positives = new Array();
var negatives = new Array();

var server1 = new mongodb.Server('localhost',27017, {auto_reconnect: true});
var db1 = new mongodb.Db('clicker', server1);   

db1.open(function(err, db) {
    if(!err) {

        db1.collection('feedback', function(err, collection) {
            for (var i=0;i <5; i++) {
                collection.find(
                    {value:1},
                    {created_on: 
                        {       
                            $gte:startTime + (i*60*1000 - 30*1000),
                            $lt: startTime + (i*60*1000 + 30*1000)
                        }
                    },
                    function(err_positive, result_positive) {
                        result_positive.count(function(err, count){
                                console.log("Total matches: " + count);
                                positives[i] = count;
                        });
                    }

                );              

                collection.find(
                    {value:0},
                    {created_on: 
                        {
                            $gte:startTime + (i*60*1000 - 30*1000),
                            $lt: startTime + (i*60*1000 + 30*1000)
                        }
                    },
                    function(err_negative, result_negative) {
                        result_negative.count(function(err, count){
                                console.log("Total matches: " + count);
                                negatives[i] = count;
                        });
                    }   
                );                                  
            }

        });

    } else {
        console.log('Error connecting to the database');
    }      

});

Actually, I am trying to get some values from the database. And then I need to manipulate these values. It's just that I need to subtract negative count from positive count and then initialize the value array with positivecount-negative count. Now since the results are obtained asynchronously. How am I supposed to manipulate those values and put them in the values array.

4

1 に答える 1

10

さらに説明する前に、コードにバグがあることに注意してください。

function(err_positive, result_positive) {
    result_positive.count(function(err, count){
        console.log("Total matches: " + count);
        positives[i] = count;  // <--- BUG: i id always 5 because it
    });                        //           is captured in a closure
}

古典的な閉鎖とループの問題。参照:ループでの JavaScript クロージャーの使用について説明してください

次に、ループ内で非同期関数を処理する方法について説明します。基本的な考え方は、完了した非同期呼び出しの数を追跡し、最後の呼び出しが返されたらコードを実行する必要があるということです。例えば:

var END=5;
var counter=end;
for (var i=0;i<END; i++) {
  collection.find(
    {value:1},
    {created_on: 
      {       
        $gte:startTime + (i*60*1000 - 30*1000),
        $lt: startTime + (i*60*1000 + 30*1000)
      }
    },
    (function(j){
      return function(err_positive, result_positive) {
        result_positive.count(function(err, count){
            console.log("Total matches: " + count);
            positives[j] = count;
        });

        counter--;
        if (!counter) {
          /*
           * Last result, now we have all positives.
           *
           * Add code that need to process the result here.
           *
           */
        }
      }
    })(i)
  ); 
}

しかし、これを続けていくと、大量の一時変数を作成することになり、恐ろしくネストされたコードになってしまうことは明らかです。しかし、これは JavaScript であるため、このパターンのロジックを関数にカプセル化できます。これが、この「すべてが完了するのを待つ」ロジックの javascript での実装です: node.js での並列実行の調整

しかし、node.js を使用しているので、便利な async モジュール フォーム npm を使用できます: https://npmjs.org/package/async

非同期を使用すると、次のようにコードを記述できます。

var queries = [];

// Build up queries:
for (var i=0;i <5; i++) {
  queries.push((function(j){
    return function(callback) {
      collection.find(
        {value:1},
        {created_on: 
          {       
            $gte:startTime + (j*60*1000 - 30*1000),
            $lt: startTime + (j*60*1000 + 30*1000)
          }
        },
        function(err_positive, result_positive) {
          result_positive.count(function(err, count){
            console.log("Total matches: " + count);
            positives[j] = count;          
            callback();
          });
        }

      );
    }
  })(i));
  queries.push((function(j){
    return function(callback) {
      collection.find(
        {value:0},
        {created_on: 
          {
            $gte:startTime + (j*60*1000 - 30*1000),
            $lt: startTime + (j*60*1000 + 30*1000)
          }
        },
        function(err_negative, result_negative) {
          result_negative.count(function(err, count){
            console.log("Total matches: " + count);
            negatives[j] = count;
            callback();
          });
        }   
      );
    }
  })(i));  
}

// Now execute the queries:
async.parallel(queries, function(){
  // This function executes after all the queries have returned
  // So we have access to the completed positives and negatives:

  // For example, we can dump the arrays in Firebug:
  console.log(positives,negatives);
});
于 2012-11-04T19:51:54.463 に答える