无法循环MongoDB集合函数

时间:2014-01-24 03:32:24

标签: node.js node-mongodb-native

出于某种原因,我无法循环collection.count。它保持打印filename[5] 5次,而不是从1开始,然后转到5.

这没有任何意义,因为我可以手动复制并粘贴此功能5次并且它可以工作,但是在for循环中,它不会。

for( var k =0; k<(filename.length)-2;k++) {

    collection.count( { "display.Name": filename[k] } , function(err, count) {
        console.log("Filename: " +filename[k]);
        console.log(" Trips: " + count);

    }); 

} 

注意:如果我将console.log放在collection.count之外,我会看到我的所有5个文件名。只有在特定功能内它才能起作用。

1 个答案:

答案 0 :(得分:4)

让我试着解释一下这一点,而不是一句话,并抛出许多有趣的术语,如“异步”,“范围链”或“封闭”。

问题出现是因为你的循环在第一个MongoDB查询返回之前很久就完成了。当您的回调运行时,变量k已循环5次,现在等于5.因此,当您的所有五个回调都返回console.log("Filename: " + filename[k]);时,console.log("Filename: " + filename[5]);将为{{1}每一次。

正在进行正确的查询,因为新的查询在循环的每次迭代中开始,并且当它处于正确的值时使用k;但是,变量k在您的回调范围范围内定义,因此当回调最终触发时,k将很长时间内完成并增加到5。

请改为尝试:

for( var k =0; k<(filename.length)-2;k++) {
    (function (k) {
        collection.count( { "display.Name": filename[k] } , function(err, count) {
            console.log("Filename: " +filename[k]);
            console.log(" Trips: " + count);
        }); 
    })(k);
}

现在它会起作用,因为我们围绕变量k创建了一个新范围。外行人所说的一切意味着,从技术上讲,你有两个变量名为k。第一个是你在for循环中定义的那个,第二个是在自调用函数调用自身时创建的那个,传入k。函数的参数也称为k,但它在技术上是一个全新的变量定义。这意味着第二个k变量将在循环的每次迭代中 NOT 更改,只有外部范围中的变量才会发生变化。

在每次迭代时定义一个新的匿名函数,并将k传递给它。现在,当回调触发时,每个k变量都将是唯一的,并且不会与外部k变量相同。

为了让事情更容易理解,只需更改匿名函数中的变量名称,使其与外部函数不同,然后您就会明白为什么会这样。

for( var k =0; k<(filename.length)-2;k++) {
    (function (x) {
        collection.count( { "display.Name": filename[x] } , function(err, count) {
            console.log("Filename: " +filename[x]);
            console.log(" Trips: " + count);
        }); 
    })(k);
}

完成同样事情的另一种奇特方法是仅将回调函数包装在新范围中而不是整个查询中。虽然我会让你自己决定是否真的更容易阅读:P

for( var k =0; k<(filename.length)-2;k++) {
    collection.count( { "display.Name": filename[k] } , (function (x) {
        return function(err, count) {
            console.log("Filename: " +filename[x]);
            console.log(" Trips: " + count);
        };
    })(k)); 
}

在这一个中,自调用函数作为collection.count的第二个参数提供。自调用函数传递k,在自调用函数中变为x。它立即返回另一个函数;实际作为第二个参数传递给collection.count的函数。自调用函数变成了一种迷你工厂,它返回另一个函数,它现在可以引用外部作用域中定义的变量(自调用函数内的作用域),我们知道它不会改变,因为从技术上来说有一个新的在每次迭代中都定义了匿名函数(带有x参数定义)。

换句话说,我确定你明白你定义的回调函数被定义了五次;每次迭代循环一次。同样适用于匿名自我调用功能。它也被创建了五个单独的时间,包括它的参数,现在它被锁定到调用函数时k的值。

希望这是有道理的。这不是一个复杂的概念,因为试图清楚地解释它是很复杂的。