Node JS / MongoDB中的嵌套查询

时间:2014-03-19 04:56:35

标签: javascript node.js mongodb

我在mongo中的用户列表表设置如下:

email: email@email.com, uniqueUrl:ABC, referredUrl: ...

我有以下代码,我查询数据库中的所有用户,并为每个用户查找有多少其他用户' referUrl等于当前用户的唯一网址:

exports.users = function(db) {
  return function(req, res) {
    db.collection('userlist').find().toArray(function (err, items) {
      for(var i = 0; i<= items.length; i++) {
        var user = items[i];
        console.log(user.email);
        db.collection('userlist').find({referredUrl:user.uniqueUrl}).count(function(err,count) {
          console.log(count);
        });
      }
    });
  };
};

现在我首先记录用户的电子邮件,然后记录与用户相关的计数。所以控制台看起来应该是这样的:

bob@bob.com
1
chris@chris.com
3
grant@grant.com
2

相反,它看起来像这样:

bob@bob.com
chris@chris.com
grant@grant.com
1
3
2

发生了什么?为什么嵌套查询仅在第一个查询完成后返回?

2 个答案:

答案 0 :(得分:3)

欢迎使用异步编程和回调。

您期望发生的是一切都以线性顺序工作,但这不是节点的工作方式。整个主题在这里有点过于宽泛,但可以阅读一些内容。

幸运的是,驱动程序调用了process.nextTick的所有键的方法,它为您提供了查找和搜索的功能。但是由于事物排队的自然方式,有一种简单的方法来修复代码。

db.collection('userlist').find().toArray(function(err,items) {
  var processing = function(user) {
    db.collection('userlist').find({ referredUrl: user.uniqueUrl })
      .count(function(err,count) {
        console.log( user.email );
        console.log( count );
    });
  };
  for( var i = 0; i < items.length; i++) {
    var user = items[i];
    processing(user);
  }
});

当然,这实际上是一种过于简化的解释方式,但在此理解您将参数传递给重复.find(),然后在那里完成所有输出。

如上所述,幸运的是,一些工作是在API函数中完成的,并且在添加调用时会保留事件堆栈。但大多数情况下,现在输出调用一起并且不会发生在不同的事件集中。

有关事件循环和回调的详细说明,我确信那里有比我在这里写的更好的。

答案 1 :(得分:2)

回调在node.js中是异步的。因此,您的计数函数(function(err,count) { console.log(count); })不会在console.log(user.email);之后立即执行。因此,输出是正常的,没有任何问题。编码风格有什么不对。当你在python中以相同的方式调用函数时(单线程),你不应该连续调用回调来获得相同的结果。要获得所需的结果,您应该在单个回调中完成所有工作。但在此之前,我建议您了解回调在nodejs中的工作原理。这将极大地帮助您在nodejs中编码