pymongo.errors.CursorNotFound: 游标 ID '...' 在服务器上无效

88 投票
7 回答
64192 浏览
提问于 2025-04-18 09:39

我正在尝试用以下代码从Mongo数据库中获取一些ID:

client = MongoClient('xx.xx.xx.xx', xxx)
db = client.test_database
db = client['...']
collection = db.test_collection
collection = db["..."]


for cursor in collection.find({ "$and" : [{ "followers" : { "$gt" : 2000 } }, { "followers" : { "$lt" : 3000 } }, { "list_followers" : { "$exists" : False } }] }): 
    print cursor['screenname']
    print cursor['_id']['uid']
    id = cursor['_id']['uid']

但是,过了一会儿,我收到了这个错误:

pymongo.errors.CursorNotFound: 游标ID '...' 在服务器上无效。

我找到了一篇文章,里面提到了这个问题。不过我不太明白该选择哪个解决方案。使用find().batch_size(30)是否可行?上面的命令到底是干什么的?我能通过batch_size获取所有数据库的ID吗?

7 个回答

2

find方法中,将batch_size设置为一个更小的数字。这个数字代表返回记录的数量。这些记录应该在10分钟内处理完(这是服务器默认的游标超时时间)。否则,游标会在服务器上关闭。
所以,batch_size的合适值可以通过以下方式找到:

collection.find({...}, batch_size=20)
6

这是一个超时问题,默认情况下,MongoDB的超时时间是10分钟。

我更喜欢通过登录MongoDB并运行一个管理员查询来解决这个问题:

use admin 
db.runCommand({setParameter:1, cursorTimeoutMillis: 1800000})

这里的1800000相当于30分钟,这对我的使用情况来说是足够的。

或者在终端中(10800000==3小时):

sudo mongod --setParameter cursorTimeoutMillis=10800000
9

你使用游标的时间超过了超时时间(大约10分钟),所以游标不再存在了。

你应该选择一个较小的批处理大小来解决这个问题:

(比如使用Pymongo)

col.find({}).batch_size(10)

或者

把超时时间设置为不限制 col.find(timeout=False),最后别忘了关闭游标。

56

你可以通过使用 no_cursor_timeout=True 让光标不超时,像这样:

cursor=db.images.find({}, {'id':1, 'image_path':1, '_id':0}, no_cursor_timeout=True)
for i in cursor:
    # .....
    # .....
cursor.close() # use this or cursor keeps waiting so ur resources are used up

之前这个功能叫做 timeout,但根据文档已经被更改了,具体可以查看这里。如果想了解更多支持 no_cursor_timeout 的方法,可以参考这个 pymongo 文档的搜索结果。

126

你遇到这个错误是因为服务器上的游标超时了(在没有任何操作的情况下,10分钟后会超时)。

根据pymongo的文档:

在MongoDB中,如果游标长时间没有进行任何操作,它可能会在服务器上超时。这会导致在尝试遍历游标时出现CursorNotFound异常。

当你调用collection.find方法时,它会查询一个集合,并返回一个指向文档的游标。要获取这些文档,你需要遍历这个游标。当你遍历游标时,驱动程序实际上是在向MongoDB服务器请求更多数据。每次请求返回的数据量是由batch_size()方法设置的。

根据文档

限制每批返回的文档数量。每批都需要与服务器进行一次往返请求。可以调整这个值来优化性能并限制数据传输。

将batch_size设置为较小的值可以帮助你解决超时错误,但这会增加你访问MongoDB服务器的次数,以获取所有文档。

默认的批量大小:

对于大多数查询,第一批返回101个文档,或者返回足够超过1兆字节的文档。批量大小不会超过最大BSON文档大小(16 MB)。

没有一个通用的“正确”批量大小。你应该尝试不同的值,看看哪个值适合你的使用场景,也就是在10分钟内你能处理多少文档。

最后的办法是设置no_cursor_timeout=True。但你需要确保在处理完数据后关闭游标。

如何在不使用try/except的情况下避免这个问题:

cursor = collection.find(
     {"x": 1},
     no_cursor_timeout=True
)
for doc in cursor:
    # do something with doc
cursor.close()

撰写回答