我为MongoDB和PyMongo 2.6.3设置了一个简单的单客户端设置。目标是迭代集合collection
中的每个文档并更新(save
)流程中的每个文档。我正在使用的方法看起来大致如下:
cursor = collection.find({})
index = 0
count = cursor.count()
while index != count:
doc = cursor[index]
print 'updating doc ' + doc['name']
# modify doc ..
collection.save(doc)
index += 1
cursor.close()
问题是save
显然正在修改游标中文档的顺序。例如,如果我的集合由3个文档组成(id
s省略清晰度):
{
"name": "one"
}
{
"name": "two"
}
{
"name": "three"
}
上述程序输出:
> updating doc one
> updating doc two
> updating doc two
但是,如果删除了行collection.save(doc)
,则输出变为:
> updating doc one
> updating doc two
> updating doc three
为什么会这样?安全地迭代和更新集合中文档的正确方法是什么?
答案 0 :(得分:12)
在MongoDB documentation中找到答案:
由于游标在其生命周期内未被隔离,因此对文档进行干预写操作可能会导致游标在文档发生更改时多次返回文档。要处理此情况,请参阅有关snapshot mode。
的信息
光标上启用了快照模式,这是一个很好的保证:
snapshot()
遍历_id
字段上的索引,并保证查询将返回每个文档(相对于_id
字段的值)不超过一次。
使用PyMongo启用快照模式:
cursor = collection.find(spec={},snapshot=True)
根据PyMongo find()
documentation。确认这解决了我的问题。
答案 1 :(得分:5)
快照完成工作。
但是在pymongo 2.9和之后,语法略有不同。
cursor = collection.find(modifiers={"$snapshot": True})
或任何版本,
cursor = collection.find({"$snapshot": True})
答案 2 :(得分:1)
我无法重新创建你的情况,但也许,在我的头脑中,因为获取结果就像你正在做的那样从db中逐一获取它们,你实际上是在创建更多的东西(保存)然后获取下一个)。
您可以尝试将结果保存在列表中(这样,您可以立即获取所有结果 - 可能很重,具体取决于您的查询):
cursor = collection.find({})
# index = 0
results = [res for res in cursor] #count = cursor.count()
cursor.close()
for res in results: # while index != count //This will iterate the list without you needed to keep a counter:
# doc = cursor[index] // No need for this since 'res' holds the current record in the loop cycle
print 'updating doc ' + res['name'] # print 'updating doc ' + doc['name']
# modify doc ..
collection.save(res)
# index += 1 // Again, no need for counter
希望有所帮助