MongoDB shell:通过未执行的游标进行嵌套迭代

时间:2017-06-11 11:45:46

标签: javascript mongodb

如果有两个嵌套的cursor.forEach()函数,则第二个函数不会被执行。 while循环也是如此:

我想通过将文档移动到另一个集合并检查是否存在重复项来从大型集合中删除重复项。我在mongo shell中运行以下代码:

var fromColl = db.from.find(),
    toColl;

fromColl.forEach(function(fromObj){
    toColl = db.to.find({name: fromObj.name});
    if (toColl.length() == 0) {
        //no duplicates found in the target coll, insert
        db.to.insert(fromObj);
    } else {
        //possible duplicates found in the target coll
        print('possible duplicates: ' + toColl.length());
        toColl.forEach(function(toObj){
            if (equal(fromObj.data, toObj.data)) {
                //duplicate...
            }
        });
    }
});

在else块中打印toColl.length(),但不执行第二个forEach循环。有谁知道为什么?

1 个答案:

答案 0 :(得分:1)

---替代方法---

我找到了一个解决方法,并创建了第二个游标的数​​组:toColl = db.to.find({name: fromObj.name}).toArray();我用一个普通的JS循环迭代数组:

var fromColl = db.from.find(),
    toColl,
    toObj;

fromColl.forEach(function(fromObj){
    toColl = db.to.find({name: fromObj.name}).toArray();
    if (toColl.length == 0) {
        //no duplicates found in the target coll, insert
        db.to.insert(fromObj);
    } else {
        //possible duplicates found in the target coll
        print('possible duplicates: ' + toColl.length());
        for (var i = 0; i < toColl.length; i++) {
            toObj = toColl[i];
            if (equal(fromObj.data, toObj.data)) {
                //duplicate...
            }
        });
    }
});

---更新---

Stephen Steneker指出:

mongo shell有一些用于处理shell中数据的快捷方式。 MongoDB文档中对此进行了更详细的解释:Iterate a Cursor in the mongo Shell

特别是:

  

如果使用var关键字未将返回的光标分配给变量,则光标最多会自动迭代20次,以打印结果中的前20个文档。

在代码示例中,var的{​​{1}}声明在执行toColl之前。

使用find()迭代所有结果是一种可能的方法,但需要将游标返回的所有文档加载到RAM中。手动迭代光标是一种更具伸缩性的方法。

- 解决方案 -

主要问题是使用toArray()代替toColl.length()

因为toColl.count()重置了光标。

非常感谢MongoDB user group的Rhys Campbell和Stephen Steneker帮助解决这个问题。