你在用 db.collection.find() 的时候,它返回的不是所有的数据,而实际上是一个“cursor”。它的默认行为是:第一次向数据库查询 101 个文档,或 1 MB 的文档,取决于哪个条件先满足;之后每次 cursor 中的文档用尽后,查询 4 MB 的文档。另外,find() 的默认行为是返回一个 10 分钟无操作后超时的 cursor。如果我一个 batch 的文档十分钟内没处理完,过后再处理完了,再用同一个 cursor id 向服务器取下一个 batch,这时候 cursor id 当然已经过期了,这也就能解释为啥我得到 cursor id 无效的错误了。
Stack Overflow 上有人提出过解决方法,是在 find() 时传入 timeout=False 来禁用 10 分钟超时的保护措施。但是我觉得这是非常差的办法,因为如果你循环时产生异常,甚至断电或断网,都会导致 MongoDB 服务器资源永远无法被释放。而更好的办法是(我也发在了 Stack Overflow 上),估计一个 batch 大小,让 MongoDB 客户端每次抓取的文档在 10 分钟内能用完,这样客户端就不得不 10 分钟内至少联系服务器一次,保证 cursor 不超时。
具体用法:
for document in db.collection.find().batch_size(30):