我有困难在选区数据的对象循环,在MongoDB中找到现有的条目,并与他们做一些事情。它总是以相同的条目一遍又一遍地在DB中被找到而告终。
我认为这是一个范围和时间的问题。
我的代码:for (key in jsonObj) {
var newConstituent = new Constituent({
name : jsonObj[key]["Name"],
email : jsonObj[key]["Email"],
social : {
twitter: {
twitter_handle : jsonObj[key]["Twitter handle"],
twitter_id : jsonObj[key]["User id"],
timestamp : jsonObj[key]["Timestamp"]
}
}
});
console.log(jsonObj[key]["Email"]); // this is fine here!
Constituent.findOne({ email : jsonObj[key]["Email"] }, function(err, constitutents){
console.log(jsonObj[key]["Email"]); // here it's always the same record
if (err) {
console.log(err)
}
if (constitutents === 'null') {
console.log("Constituent not found. Create new entry .. ");
// console.log(newConstituent);
newConstituent.save(function (err) {
if (err) {
console.log('db save error');
}
});
} else {
console.log("Constituent already exists .. ");
}
});
}
我怀疑for循环比. findone()执行得更快,因此总是只获得传递给find的对象的最后一项。
谁能给我指个正确的方向?这几个
-
不要使用
for ... in
,特别是在node中。你可以使用Object.keys()
和任何数组方法。for ... in
可以包括你不希望循环的值,除非你使用hasOwnProperty
,因为它将包括来自原型链的值。 -
邮件相同的原因是你只是再次打印出你的查询。
jsonObj
包含在findOne
的回调范围中,因为您没有在findOne
回调中重新声明它。因此,当调用回调时,无论key
的值是多少(我猜它是您列表中的最后一个),都是您收到的电子邮件。因为,在javascript中,内部函数作用域总是隐式地包括周围上下文的作用域,所以您只是从封闭作用域访问jsonObj
。为了澄清这一点,您的
for ... in
循环是同步的——即解释器在处理任何新指令之前完成其中所有指令的运行。findOne
, how ever是异步的。很简单,当你在这个循环中调用它时,它实际上并没有立即做任何事情——解释器仍然在运行你的for ... in
循环。但是,它会向执行堆栈中添加更多任务,以便在完成循环后运行。这样循环就结束了,然后你的回调函数将开始执行。由于for ... in
循环完全完成,因此key
被设置为它的最终值。因此,例如,如果它的最后一个值是foo
,这意味着每次你的回调被调用时,你将打印出jsonObj.foo
,因为for ... in
循环已经完成。所以这就像你让你的朋友说出从A到J的字母,而你离开房间去做10件事。做点什么。他完全去了J,因为这比你做10件事中的1件要快得多。现在每次你做完一件事,你回来问"你最近写的是什么信"。答案永远是j。如果你需要知道他在每一个任务的哪个字母上,你要么需要让他在你做的时候停止计数,要么以某种方式获得关于哪个字母与你正在执行的任务数量相对应的信息。
让他们等不是个好主意——这是浪费他们的时间。但是,如果将findOne
包装在一个新函数中,并传入key
的值,则可以正常工作。 -
我不确定你的数据,但
findOne
将返回一条记录。您将它放入一个复数变量(constitutents
)。从阅读你的代码,我希望回到一个单一的值在这里。(它可能仍然被包装在一个数组中)
由于调用findOne
并将find操作的结果赋值给constituent
,因此应该在console.log
中检查该对象。
。
console.log(constitutents.email); // or console.log(constitutents[0].email)
而不是
console.log(jsonObj[key]["Email"]);
(假设email
是constituants
的属性)。
你可以尝试完全记录constituants
来验证你在寻找什么。
下面的代码能够工作的原因是每次调用都将key
的当前值传递给函数。这意味着每次调用findConstituent
时都会创建该变量的本地副本,而不是使用该变量的闭包值。
var newConstituent;
function findConstituent(key){
Constituent.findOne({ email : jsonObj[key]["Email"] }, function(err, constitutents){
console.log(jsonObj[key]["Email"]); // here it's always the same record
if (err) {
console.log(err)
}
if (constitutents === 'null') {
console.log("Constituent not found. Create new entry .. ");
// console.log(newConstituent);
newConstituent.save(function (err) {
if (err) {
console.log('db save error');
}
});
} else {
console.log("Constituent already exists .. ");
}
});
}
for (key in jsonObj) {
newConstituent = new Constituent({
name : jsonObj[key]["Name"],
email : jsonObj[key]["Email"],
social : {
twitter: {
twitter_handle : jsonObj[key]["Twitter handle"],
twitter_id : jsonObj[key]["User id"],
timestamp : jsonObj[key]["Timestamp"]
}
}
});
findConstituent(key);
}