如何使用 insert_many 安全地忽略重复的键错误
Posted
技术标签:
【中文标题】如何使用 insert_many 安全地忽略重复的键错误【英文标题】:How to Ignore Duplicate Key Errors Safely Using insert_many 【发布时间】:2017-12-03 22:20:36 【问题描述】:在使用 pymongo 的 insert_many 时,我需要忽略重复插入,其中重复项基于索引。我在 *** 上看到过这个问题,但我没有看到有用的答案。
这是我的代码 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, 是的,这个问题以前曾被问过,遗憾的是没有一个答案令人满意。因此,重新发布的原因。但在这种情况下,答案是正确且有用的。
【参考方案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 以来的延迟.以上是关于如何使用 insert_many 安全地忽略重复的键错误的主要内容,如果未能解决你的问题,请参考以下文章
使用 Jackson 忽略 JSON 对象上的新字段 [重复]
Spring 安全忽略 url 不适用于我们的安全忽略方法 [重复]
[pyMongo]insert_many的Bulkwrite实现机制