pymongo.errors.CursorNotFound:光标id' ...'在服务器上无效

时间:2014-06-13 07:18:20

标签: python mongodb pymongo

我正在尝试使用以下代码获取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:cursor id'...'在服务器上无效。

我发现这个article引用了这个问题。然而,我不清楚采取哪种解决方案。是否可以使用find().batch_size(30)?上面的命令到底是做什么的?我可以使用batch_size

获取所有数据库ID

6 个答案:

答案 0 :(得分:70)

您收到此错误是因为光标在服务器上超时(10分钟不活动后)。

来自pymongo文档:

  

如果MongoDB中的游标已经打开,它们可以在服务器上超时   很长一段时间没有对它们进行任何操作。这个可以   导致尝试时引发的CursorNotFound异常   迭代光标。

当您调用collection.find方法时,它会查询集合并将光标返回到文档。要获取文档,请迭代光标。迭代游标时,驱动程序实际上是向MongoDB服务器发出请求以从服务器获取更多数据。每个请求中返回的数据量由batch_size()方法设置。

来自documentation

  

限制一批中返回的文档数量。每批   需要往返服务器。它可以调整以优化   性能和限制数据传输。

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

默认批量大小:

  

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

没有通用的“正确”批量大小。您应该使用不同的值进行测试,看看您的用例的适当值是什么,即您可以在10分钟的窗口中处理多少文档。

最后的手段是你设置timeout=False。但是,在完成数据处理后,您需要确保光标已关闭。

答案 1 :(得分:41)

像这样使用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

答案 2 :(得分:3)

您使用的光标超过了超时(大约10分钟),因此光标不再存在。

您应该选择较低的batch_size值来解决问题:

(以Pymongo为例)

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

将超时设置为false col.find(timeout=False)并且不要忘记最后关闭光标。

答案 3 :(得分:1)

batch_size方法中的find设置为较小的数字。该数量是返回记录的数量。这些记录的处理速度应超过10分钟(默认服务器光标超时)。否则,游标将在服务器上关闭。
因此,应使用next找到适合batch_size的值:

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

答案 4 :(得分:1)

您可以将游标对象转换为一个列表然后使用它,这样您就不再实际从该游标进行调用,而是来自一个本地列表。因此,您的代码在该游标上执行这些操作所花费的时间比仅将游标复制到列表所花费的时间要长得多。因此在复制到列表时超时的可能性非常低。因此,一旦完成,它会在特定时间后超时,但无论如何您不再提及它,您将使用自己的列表。

Cursor = collection.find({ "$and" : [{ "followers" : { "$gt" : 2000 } }, { "followers" : { "$lt" : 3000 } }, { "list_followers" : { "$exists" : False } }] })
Cursor = [x for x in Cursor]

现在对这个列表做任何事情,你已经获取了其中的所有记录。

例如 -

for i in Cursor:
    print(i['screenname'])

答案 5 :(得分:0)

这是一个超时问题,默认情况下,在mongodb中为10分钟。 我更喜欢通过登录mongo并运行管理员查询更新来解决此问题:

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

其中1800000相当于30分钟,对于我的用例而言,就足够了。

或在终端(10800000 == 3h):

sudo mongod --setParameter cursorTimeoutMillis=10800000