pymongo.errors.CursorNotFound: 游标 ID '...' 在服务器上无效
我正在尝试用以下代码从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 个回答
在find
方法中,将batch_size
设置为一个更小的数字。这个数字代表返回记录的数量。这些记录应该在10分钟内处理完(这是服务器默认的游标超时时间)。否则,游标会在服务器上关闭。
所以,batch_size
的合适值可以通过以下方式找到:
collection.find({...}, batch_size=20)
这是一个超时问题,默认情况下,MongoDB的超时时间是10分钟。
我更喜欢通过登录MongoDB并运行一个管理员查询来解决这个问题:
use admin
db.runCommand({setParameter:1, cursorTimeoutMillis: 1800000})
这里的1800000相当于30分钟,这对我的使用情况来说是足够的。
或者在终端中(10800000==3小时):
sudo mongod --setParameter cursorTimeoutMillis=10800000
你使用游标的时间超过了超时时间(大约10分钟),所以游标不再存在了。
你应该选择一个较小的批处理大小来解决这个问题:
(比如使用Pymongo)
col.find({}).batch_size(10)
或者
把超时时间设置为不限制 col.find(timeout=False)
,最后别忘了关闭游标。
你可以通过使用 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 文档的搜索结果。
你遇到这个错误是因为服务器上的游标超时了(在没有任何操作的情况下,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()