如何循环对象&为每个项返回mongoDB条目?

时间:2014-08-05 15:08:47

标签: node.js mongodb loops for-loop

我在圈选选区数据的对象时遇到了困难,在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的对象的最后一项。

有人能指出我正确的方向吗?

1 个答案:

答案 0 :(得分:2)

其中几个。

  1. 不要使用for ... in,尤其是在节点中。此时您可以使用Object.keys()和任何数组方法。 for ... in可以包含您不希望循环的值,除非您使用hasOwnProperty,因为它会包含原型链中的值。

  2. 电子邮件相同的原因是您只是再次打印出您的查询。 jsonObj的回调范围中包含findOne,因为您未在findOne回调中重新声明它。因此,无论key的值是什么(我的猜测是它是列表中的最后一个),当回调被调用时,就是您收到的电子邮件。因为在javascript中,内部函数作用域总是隐含地包含周围上下文的范围,所以您只需从封闭范围访问jsonObj

    为了澄清这一点,您的for ... in循环是同步的 - 即解释器在处理任何新指令之前完成运行其中的所有指令。 findOne,如何异步。很简单,当你在这个循环中调用它时,它实际上并没有立即执行任何操作 - 解释器仍在运行你的for ... in循环。但是,它会在执行堆栈中添加更多任务,以便在完成循环后运行。所以循环结束了,然后你的回调将开始执行。由于for ... in循环完全完成,key被设置为它的最终值。因此,例如,如果它的最后一个值是foo,这意味着每次调用您的回调,则由于jsonObj.foo循环已经完成,您将打印出for ... in。< / p>

    所以就像你要求你的朋友说出A到J的信件一样,你离开了房间做了10件事。做某事。他完全去了J,因为这比你正在做的10件事中的一件要快得多。现在,每当你做完你的某件事,你就会回来说出你所说的最新信#34;&#34;。答案将永远是J.如果您需要知道他为每项任务写了什么信,您需要让他在您执行此操作时停止计数或以某种方式获取有关哪些字母与数字相对应的信息你正在执行的任务。

    让他们等待并不是一个好主意 - 这是浪费他们的时间。但是,如果您将findOne包装在传递key值的新函数中,这将起作用。请参阅下面的更新代码。

  3. 我不确定您的数据,但findOne会返回一条记录。您将其放入具有复数(constitutents)的变量中。通过阅读您的代码,我希望在这里返回一个值。 (但它可能仍然包含在数组中。)

  4. 由于您正在调用findOne并将查找操作的结果分配给constituent,因此您应该在console.log中检查该对象。

    e.g。

    console.log(constitutents.email); // or console.log(constitutents[0].email)
    

    而不是

    console.log(jsonObj[key]["Email"]);
    

    (假设emailconstituants上的属性。

    您可以尝试完全记录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);
    }