Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js MongoDB-错误:getMore命令失败:找不到光标_Node.js_Mongodb_Mongodb Query_Cursor - Fatal编程技术网

Node.js MongoDB-错误:getMore命令失败:找不到光标

Node.js MongoDB-错误:getMore命令失败:找不到光标,node.js,mongodb,mongodb-query,cursor,Node.js,Mongodb,Mongodb Query,Cursor,我需要在大约500K个文档的集合中的每个文档上创建一个新字段sid。每个sid都是唯一的,并且基于该记录的现有roundedDate和stream字段 我使用以下代码执行此操作: var cursor = db.getCollection('snapshots').find(); var iterated = 0; var updated = 0; while (cursor.hasNext()) { var doc = cursor.next(); if (doc.stre

我需要在大约500K个文档的集合中的每个文档上创建一个新字段
sid
。每个
sid
都是唯一的,并且基于该记录的现有
roundedDate
stream
字段

我使用以下代码执行此操作:

var cursor = db.getCollection('snapshots').find();
var iterated = 0;
var updated = 0;

while (cursor.hasNext()) {
    var doc = cursor.next();

    if (doc.stream && doc.roundedDate && !doc.sid) {
        db.getCollection('snapshots').update({ "_id": doc['_id'] }, {
            $set: {
                sid: doc.stream.valueOf() + '-' + doc.roundedDate,
            }
        });

        updated++;
    }

    iterated++;
}; 

print('total ' + cursor.count() + ' iterated through ' + iterated + ' updated ' + updated);
它一开始运行良好,但几小时后,大约10万条记录出现错误:

Error: getMore command failed: {
    "ok" : 0,
    "errmsg": "Cursor not found, cursor id: ###",
    "code": 43,
}: ...

编辑-查询性能: 正如@NeilLunn在他的评论中指出的,您不应该手动筛选文档,而应该使用
。查找(…)

db.snapshots.find({
    roundedDate: { $exists: true },
    stream: { $exists: true },
    sid: { $exists: false }
})
此外,使用MongoDB 3.2中提供的工具将比单独进行更新更有效

这样,您就有可能在游标的10分钟生命周期内执行查询。如果仍然需要更多时间,则光标将过期,并且您仍将遇到相同的问题,如下所述:

这里发生了什么:
错误:getMore命令失败
可能是由于光标超时,这与两个光标属性有关:

  • 超时限制,默认为10分钟:

    默认情况下,服务器将在10分钟不活动后自动关闭光标,或者如果客户端耗尽了光标

  • 批大小,第一批为101个文档或16MB,后续批为16MB,与文档数量无关(从MongoDB
    3.4开始):

    find()
    aggregate()
    操作的初始批处理大小默认为101个文档。针对结果游标发出的后续操作没有默认的批处理大小,因此它们仅受16MB消息大小的限制

可能您正在使用最初的101个文档,然后得到一个16MB的批处理,这是最大的批处理,其中包含更多的文档。由于处理这些文档需要10分钟以上的时间,服务器上的光标将超时,当您处理完第二批文档时,光标已关闭:

在遍历游标并到达返回批处理的末尾时,如果有更多结果,cursor.next()将执行getMore操作以检索下一批处理


可能的解决方案: 我认为有5种可能的方法可以解决这个问题,3种是好的,各有利弊,还有2种是坏的:


  • 这是mongodb服务器会话管理中的一个bug。当前正在进行修复,应在4.0中修复+

    (转载于MongoDB 3.6.5)


    添加
    collection.find().batchSize(20)
    帮助我略微降低了性能。

    我也遇到了这个问题,但对我来说,它是由MongDB驱动程序中的错误引起的

    它发生在npm包
    mongodb
    3.0.x
    版本中,例如在Meteor
    1.7.0.x
    中使用,我也在该版本中记录了这个问题。该评论中对其进行了进一步描述,该线程包含一个确认该错误的示例项目:


    将npm包更新为
    3.1.x
    为我修复了它,因为我已经考虑了@Danziger在这里给出的好建议。

    当使用Java v3驱动程序时,应该在FindOptions中设置noCursorTimeout

    DBCollectionFindOptions options =
                        new DBCollectionFindOptions()
                            .maxTime(90, TimeUnit.MINUTES)
                            .noCursorTimeout(true)
                            .batchSize(batchSize)
                            .projection(projectionQuery);        
    cursor = collection.find(filterQuery, options);
    

    在我的例子中,这是一个负载平衡问题,Node.js服务和Mongos在Kubernetes上作为pod运行时也存在同样的问题。 客户端正在使用默认负载平衡的mongos服务。
    将kubernetes服务更改为使用sessionAffinity:ClientIP
    (粘性)为我解决了问题。

    我原以为您最大的问题是这一行
    doc.stream&&doc.roundedDate&!doc.sid
    。您只需传递
    .find()
    ,而不使用任何查询表达式,而是过滤代码中的所有文档。让数据库通过移动到查询
    .find({“roundedDate”:{“$exists”:true},“stream”:{“$exists”:true},“sid”:{“$exists”:false})
    来完成这项工作。您还应该每500个左右的项使用一次,而不是在服务器上实际执行每个语句。不要重复不必要的项目,2。使用批量提交以避免服务器确认开销。应该可以节省当前流程的“小时”。您可以进行其他更改以保持光标处于活动状态,但最好的做法是基本上减少处理时间。甚至可以通过
    \u id
    上的“范围”来分解文档的选择,以进一步减少可能的选择。很棒的信息@NeilLunn。我在看bulkWrite()——在我使用bulkWrite()和updateMany()的特殊情况下,问题是我无法访问每个记录,也无法创建sid字段。不过,我一直在寻找这样的方法。我可以使用mongoose在一个数组中本地组装/更新所有记录,但我找不到在数据库中插入/更新/覆盖它们的方法。我想你误解了
    .bulkWrite()
    的用法。举一个例子来看。搞乱光标超时只会让你走这么远。您真正需要做的是减少开销。@NeilLunn感谢您指出这一点,我完全没有注意到这一点,而且实际上有可能在游标过期之前执行查询,特别是如果有索引可以匹配
    .find(…)
    查询。
    光标未找到
    错误是否由超时以外的情况引起?我想很少,但如果您进行快速搜索,您会看到由于驱动程序中的错误而发生过几次:,非常清楚,光标超时是否在下一批检索时重置(即,下次客户收到一批101份文件时)?Thanks@mils是,如果您请求新批次,且光标自上次请求后尚未过期(您仍在10分钟内)