【问题标题】:Best way to read and update mongodb documents using pymongo使用 pymongo 读取和更新 mongodb 文档的最佳方法
【发布时间】:2014-10-18 13:15:22
【问题描述】:

我正在尝试逐个文档读取 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)

但这是最好的方法吗?即如果集合很大会发生什么?大 list_coll 会导致 ram 溢出吗? 请给我建议一个最好的方法。

谢谢

【问题讨论】:

  • 我想不出更好的方法,所以我不会填写答案。推荐生成器而不是创建记录列表可能会很疯狂,因为我认为您会遇到同样的问题。我很可能会使用您的解决方案,尽管如果我要更新非常大的集合,我会在创建列表时删除不必要的值的记录,只是为了节省一些额外的空间(这可以防止“ram 溢出”)。如果您认为这是现实场景,您可能应该一次取一些集合。 (注意:您可以在修改后的记录中添加标志并使用第一个 sn-p,但需要开销)
  • 是的,但我的条纹列表也会很大,这是我的问题。
  • @wudpecker 我认为这里的真实情况是“你想做什么?”当有特定意图或通常意味着您需要“读取”一个值并修改它然后写回某些内容时,使用“nothing”查询循环是有意义的。但是,如果您只是想修改某些内容,那么通常有更好的方法。所以试着改变你的问题,说出你真正想做的事情。然后你就会得到真正的答案。
  • 感谢@NeilLunn,已编辑
  • 好的。至少意图更清晰。在我的阅读中,还有一种更好的方法尚未解决。

标签: python mongodb pymongo mongodb-query


【解决方案1】:

如果您的集合没有分片,您可以使用 snapshot 参数将您的 find 光标与更新后的同一文档隔离开来:

for record in coll.find(snapshot = True):
    #modifying record here
    coll.update(record)

如果您的集合是分片的,请保留您已更新的 _id 值的哈希变量,然后在修改每条记录之前检查该列表,以确保您不会两次更新相同的记录。

【讨论】:

【解决方案2】:

您想要来自 MongoDB 的 "Bulk Operations 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”实际上为您解决了一些问题,但您确实希望更好地“管理”它,而不是在您的应用中消耗太多内存。

未来之路。使用它。

【讨论】:

  • 这个 initialize_ordered_bulk_op() 是否适用于 pymongo 2.5
  • @wudpecker 批量插入操作是在 pymongo 2.6 和混合操作中引入的,包括从 2.7 开始的更新。主要要求是 MongoDB 2.6 或更高版本的服务器版本,如果您已经有,那么您也应该考虑升级您的客户端库。
【解决方案3】:

将每条记录标记为已更新,例如通过添加标志或确保更新的字段具有可以被查询匹配的特定形式。

使用查询仅匹配尚未更新的文档,并在迭代时仔细检查每个文档。

为什么?

  • 因为集合可能太大而无法管理本地哈希中的更新 ID

  • 因为您的进程可能会崩溃并使集合处于半更新状态。您可能希望能够恢复它。

如果这是针对非分片集合的一次性作业,请考虑使用快照查询。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-08
    • 2021-11-30
    • 2015-08-27
    • 2011-07-09
    • 2021-06-22
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    相关资源
    最近更新 更多