使用pymongo读取和更新mongodb文档的最佳方法
我正在尝试逐个读取MongoDB中的文档,以便获取每一条记录,给其中一些字段加密,然后再把它们放回数据库。
for record in coll.find():
#modifying record here
coll.update(record)
这导致了一个严重的问题,也就是说,已经更新过的文档又被游标读取,导致同一文档在循环中被再次处理(同一文档又被尝试更新)。
希望这可能是解决问题的一种方法。
list_coll = [record for record in coll.find()]
for rec in list_coll:
#modifying record
coll.update(rec)
但这样做是最好的方法吗?如果集合很大,会发生什么?大列表会导致内存溢出吗?请给我建议一个更好的方法。
谢谢。
3 个回答
0
给每条记录标记为已更新,比如可以加个标记,或者确保更新的字段有特定的格式,这样可以通过查询来匹配。
使用这个查询只匹配那些还没有更新的文档,并在遍历每个文档时再仔细检查一遍。
为什么要这样做呢?
因为数据集合可能太大,无法在本地用哈希表管理已更新的ID。
因为你的处理过程可能会崩溃,导致集合处于半更新的状态。你可能希望能够从中恢复。
如果这是在一个没有分片的集合上进行的一次性工作,可以考虑使用快照查询。
3
如果你的数据集合没有分片,你可以通过使用 snapshot
参数来避免在更新后再次看到同一条记录。这样可以让你的 find
查询结果更干净。
for record in coll.find(snapshot = True):
#modifying record here
coll.update(record)
如果你的数据集合是分片的,你需要保持一个变量,记录已经更新过的 _id
值。然后在修改每条记录之前,先检查这个列表,以确保你不会重复更新同一条记录。
9
你想要使用MongoDB的“批量操作API”。这个功能大约是在MongoDB 2.6版本中引入的,所以如果你还没有升级的话,升级是个不错的选择。
bulk = db.coll.initialize_ordered_bulk_op()
counter = 0
for record in coll.find(snapshot=True):
# now process in bulk
# calc value first
bulk.find({ '_id': record['_id'] }).update({ '$set': { 'field': newValue } })
counter += 1
if counter % 1000 == 0:
bulk.execute()
bulk = db.coll.initialize_ordered_bulk_op()
if counter % 1000 != 0:
bulk.execute()
这样做会更好,因为你不是每次都把“每一个”请求都发送到服务器,而是每1000个请求只发送一次。这个“批量API”实际上会帮你处理一些事情,但你还是想要“更好地管理”这个过程,以免在你的应用中占用太多内存。
这是未来的趋势。赶快用起来吧。