在insert_many()失败后获取插入的ID

时间:2016-02-04 01:42:55

标签: mongodb python-3.x pymongo

我目前正在尝试编写一个脚本,将文档插入MongoDb并返回存储每个元素的位置。非常简单,感谢insert_many(),但是如果在插入时出现错误,则会出现问题。

我将无法获得刚刚插入的ID。

from pymongo import MongoClient

client = MongoClient(...)
db = client.test

r = db.test.insert_many([{'foo': 1}, {'foo': 2}, {'foo': 3}])
r.inserted_ids
#: [ObjectId('56b2a592dfcce9001a6efff8'),
#:  ObjectId('56b2a592dfcce9001a6efff9'),
#:  ObjectId('56b2a592dfcce9001a6efffa')]

list(db.test.find())
#: [{'_id': ObjectId('56b2a592dfcce9001a6efff8'), 'foo': 1},
#:  {'_id': ObjectId('56b2a592dfcce9001a6efff9'), 'foo': 2},
#:  {'_id': ObjectId('56b2a592dfcce9001a6efffa'), 'foo': 3}]

# This is dead stupid, but forcing an error by re-using the ObjectId we just generated
r2 = db.test.insert_many([{'foo': 4}, {'_id': r.inserted_ids[0], 'foo': 6}, {'foo': 7}])
#: ---------------------------------------------------------------------------
#: BulkWriteError                            Traceback (most recent call last)
#: <Cut in the interest of time>

当然,r2没有初始化,所以我不能要求inserted_ids,但是,会有一条记录插入到数据库中:

list(db.test.find())
#: [{'_id': ObjectId('56b2a592dfcce9001a6efff8'), 'foo': 1},
#:  {'_id': ObjectId('56b2a592dfcce9001a6efff9'), 'foo': 2},
#:  {'_id': ObjectId('56b2a592dfcce9001a6efffa'), 'foo': 3},
#:  {'_id': ObjectId('56b2a61cdfcce9001a6efffd'), 'foo': 4}]

我想要的是能够可靠地确定按顺序插入的Id。喜欢的东西:

r2.inserted_ids
#: [ObjectId('56b2a61cdfcce9001a6efffd'),
#:  None, # or maybe even some specific error for this point.
#:  None]

设置ordered=False仍会出现错误,因此r2不会被初始化(并且无论如何都无法按照我给出的顺序可靠地返回ID)。

这里有选择吗?

2 个答案:

答案 0 :(得分:2)

pymongo sets the _id field at client side,然后再将其发送到服务器。它会修改您通过到位的文档

这意味着所有您传递的文档都会留下_id字段集 - 成功的字段和失败的字段。

所以你只需要找出哪些是成功的。这可以像@Austin解释的那样完成。

类似的东西:

docs = [{'foo': 1}, {'foo': 2}, {'foo': 3}]
try:
    r = db.test.insert_many(docs)
except pymongo.errors.OperationFailure as exc:
    inserted_ids = [ doc['_id'] for doc in docs if not is_failed(doc, exc) ]
else:
    inserted_ids = r.inserted_ids

is_failed(doc, exc)可以通过在异常详细信息中的失败文档列表中搜索doc来实现,如@Austin所述。

答案 1 :(得分:1)

抓住抛出的异常。至少根据this site,返回的错误详细信息包括错误记录。这应该使您能够确定成功的记录。