【问题标题】:How to Ignore Duplicate Key Errors Safely Using insert_many如何使用 insert_many 安全地忽略重复的键错误
【发布时间】:2017-12-03 22:20:36
【问题描述】:

在使用 pymongo 的 insert_many 时,我需要忽略重复插入,其中重复项基于索引。我在 stackoverflow 上看到过这个问题,但我没有看到有用的答案。

这是我的代码 sn-p:

try:
    results = mongo_connection[db][collection].insert_many(documents, ordered=False, bypass_document_validation=True)
except pymongo.errors.BulkWriteError as e:
    logger.error(e)

我希望 insert_many 忽略重复项而不抛出异常(这会填满我的错误日志)。或者,是否可以使用单独的异常处理程序,以便我可以忽略错误。我想念“w=0”...

谢谢

【问题讨论】:

  • 即使使用ordered=False Bulk "inserts" 仍然会抛出错误,即使整个批次实际上都已提交。选项取决于您是否要 try .. except 并本质上“忽略”重复键错误,或者如果您真的不想这样做,那么请改用“upserts”。这确实需要在每个文档上有效地“查找”,但本质上是“不能”创建重复键。这就是它的工作原理。
  • 如何忽略特定的“重复键”错误?我不想无意中忽略其他错误。
  • 好吧 BuklWriteError 或 python 中的任何特定类(需要查找),并列出数组中的每个错误。这些条目有一个错误代码 E11000 在我的脑海中。简单地处理并忽略这些,当然对存在的任何其他代码都“扔/抱怨/记录/随便什么”。
  • 这是错误字符串:“batch op errors occurred”,不是很具体。
  • 亲爱的 S.M.Styvane, 是的,这个问题以前曾被问过,遗憾的是没有一个答案令人满意。因此,重新发布的原因。但在这种情况下,答案是正确且有用的。

标签: python mongodb pymongo


【解决方案1】:

正确的解决方案是使用 w=0 和ordered=False 的WriteConcern:

import pymongo
from pymongo.write_concern import WriteConcern


mongodb_connection[db][collection].with_options(write_concern=WriteConcern(w=0)).insert_many(messages, ordered=False)

【讨论】:

    【解决方案2】:

    为 Neil 的解决方案添加更多内容。

    拥有 'ordered=False, bypass_document_validation=True' 参数允许新的待处理插入发生,即使出现重复异常。

    from pymongo import MongoClient, errors
    
    DB_CLIENT = MongoClient()
    MY_DB = DB_CLIENT['my_db']
    TEST_COLL = MY_DB.dup_test_coll
    
    doc_list = [
        {
            "_id": "82aced0eeab2467c93d04a9f72bf91e1",
            "name": "shakeel"
        },
        {
            "_id": "82aced0eeab2467c93d04a9f72bf91e1",  # duplicate error: 11000
            "name": "shakeel"
        },
        {
            "_id": "fab9816677774ca6ab6d86fc7b40dc62",  # this new doc gets inserted
            "name": "abc"
        }
    ]
    
    try:
        # inserts new documents even on error
        TEST_COLL.insert_many(doc_list, ordered=False, bypass_document_validation=True)
    except errors.BulkWriteError as e:
        print(f"Articles bulk insertion error {e}")
    
        panic_list = list(filter(lambda x: x['code'] != 11000, e.details['writeErrors']))
        if len(panic_list) > 0:
            print(f"these are not duplicate errors {panic_list}")
    

    既然我们谈论的是重复,它也值得检查this solution

    【讨论】:

      【解决方案3】:

      您可以通过检查BulkWriteError 产生的错误来解决这个问题。这实际上是一个具有多个属性的“对象”。有趣的部分在details

      import pymongo
      from bson.json_util import dumps
      from pymongo import MongoClient
      client = MongoClient()
      db = client.test
      
      collection = db.duptest
      
      docs = [{ '_id': 1 }, { '_id': 1 },{ '_id': 2 }]
      
      
      try:
        result = collection.insert_many(docs,ordered=False)
      
      except pymongo.errors.BulkWriteError as e:
        print e.details['writeErrors']
      

      在第一次运行时,这将给出e.details['writeErrors'] 下的错误列表:

      [
        { 
          'index': 1,
          'code': 11000, 
          'errmsg': u'E11000 duplicate key error collection: test.duptest index: _id_ dup key: { : 1 }', 
          'op': {'_id': 1}
        }
      ]
      

      在第二次运行时,您会看到三个错误,因为所有项目都存在:

      [
        {
          "index": 0,
          "code": 11000,
          "errmsg": "E11000 duplicate key error collection: test.duptest index: _id_ dup key: { : 1 }", 
          "op": {"_id": 1}
         }, 
         {
           "index": 1,
           "code": 11000,
           "errmsg": "E11000 duplicate key error collection: test.duptest index: _id_ dup key: { : 1 }",
           "op": {"_id": 1}
         },
         {
           "index": 2,
           "code": 11000,
           "errmsg": "E11000 duplicate key error collection: test.duptest index: _id_ dup key: { : 2 }",
           "op": {"_id": 2}
         }
      ]
      

      所以你需要做的就是过滤数组中带有"code": 11000 的条目,然后只在有其他东西时“恐慌”

      panic = filter(lambda x: x['code'] != 11000, e.details['writeErrors'])
      
      if len(panic) > 0:
        print "really panic"
      

      这为您提供了一种忽略重复键错误但当然要注意实际问题的机制。

      【讨论】:

      • 我不知道异常对象中的详细信息字段,谢谢!
      • @vgoklani 这有点隐藏,甚至没有真正记录在案:(所以即使我也不得不去挖掘它,即使我“知道它在某个地方”。因此自从我上次 cmets 以来的延迟.
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-06
      • 2017-10-16
      相关资源
      最近更新 更多