我在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
发生了什么?为什么嵌套查询仅在第一个查询完成后返回?
答案 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中编码