处理node.js和mongodb中的异步数据库查询

Handling asynchronous database queries in node.js and mongodb

我有这个问题从node.js异步查询mongodb。 这是我的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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');
    }      

});

实际上,我试图从数据库中获取一些值。 然后我需要操纵这些值。 只是我需要从正计数中减去负计数,然后使用positivecount-negative计数初始化值数组。 现在,因为结果是异步获得的。 我该如何操纵这些值并将它们放在values数组中。


在我进一步解释之前,我想指出您的代码中存在错误:

1
2
3
4
5
6
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闭包

现在,如何在循环中处理异步函数。 基本思想是,您需要跟踪已完成的异步调用次数,并在最终调用返回后运行代码。 例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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,我们可以使用方便的异步模块形式npm:https://npmjs.org/package/async

使用async,您可以像这样编写代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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);
});