查找具有重复键的批量插入中插入文档的数量

时间:2015-05-14 08:24:38

标签: mongodb pymongo tornado-motor

我正在对mongodb数据库进行批量插入。我知道插入的99%的记录会因重复键错误而失败。我想在插入后打印有多少新记录插入到数据库中。所有这一切都是通过龙卷风马达mongodb驱动程序在python中完成的,但这可能并不重要。

try:
    bulk_write_result = yield db.collections.probe.insert(dataarray, continue_on_error=True)
    nr_inserts = bulk_write_result["nInserted"]
except pymongo.errors.DuplicateKeyError as e:
    nr_inserts = ????  <--- what should I put here?

由于抛出异常,bulk_write_result为空。显然我可以(除了并发问题)在插入之前和之后对完整集合进行计数,但是我不喜欢在日志文件中只有一行到数据库的额外往返。那么有什么方法可以发现实际插入了多少条记录?

2 个答案:

答案 0 :(得分:3)

我不清楚为什么你yield插入结果。但是,关于bulk inserts

  • 您应该使用insert_many,因为insert已被弃用;
  • ordered关键字设置为False时,如果出现错误,您的插入内容将继续;
  • 如果出现错误,insert_many会引发BulkWriteError,您可以查询以获取插入的文档数。

所有这些导致类似的事情:

try:
  insert_many_result = db.collections.probe.insert_many(dataaray,ordered=False)
  nr_inserts = len(insert_many_result.inserted_ids)
except pymongo.errors.BulkWriteError as bwe:
  nr_inserts = bwe.details["nInserted"]

如果您需要识别写入错误背后的原因,则必须检查bwe.details['writeErrors']数组。代码值11000表示&#34;重复键错误&#34;:

>>> pprint(e.details['writeErrors'])
[{'code': 11000,
  'errmsg': 'E11000 duplicate key error index: test.w.$k_1 dup key: { : 1 }',
  'index': 0,
  'op': {'_id': ObjectId('555465cacf96c51208587eac'), 'k': 1}},
 {'code': 11000,
  'errmsg': 'E11000 duplicate key error index: test.w.$k_1 dup key: { : 3 }',
  'index': 1,
  'op': {'_id': ObjectId('555465cacf96c51208587ead'), 'k': 3}}

在这里,正如您所看到的,我尝试在w db的test集合中插入两个文档。由于重复的密钥错误,两个插入都失败了。

答案 1 :(得分:2)

使用continue_on_error进行常规插入无法报告您想要的信息。但是,如果您使用的是MongoDB 2.6或更高版本,我们的高性能解决方案具有良好的错误报告功能。这是使用Motor的BulkOperationBuilder的完整示例:

import pymongo.errors
from tornado import gen
from tornado.ioloop import IOLoop
from motor import MotorClient

db = MotorClient()
dataarray = [{'_id': 0},
             {'_id': 0},  # Duplicate.
             {'_id': 1}]


@gen.coroutine
def my_insert():
    try:
        bulk = db.collections.probe.initialize_unordered_bulk_op()

        # Prepare the operation on the client.
        for doc in dataarray:
            bulk.insert(doc)

        # Send to the server all at once.
        bulk_write_result = yield bulk.execute()
        nr_inserts = bulk_write_result["nInserted"]
    except pymongo.errors.BulkWriteError as e:
        print(e)
        nr_inserts = e.details['nInserted']

    print('nr_inserts: %d' % nr_inserts)


IOLoop.instance().run_sync(my_insert)

完整文档:http://motor.readthedocs.org/en/stable/examples/bulk.html

在2.6之前注意MongoDB上的批量插入性能不佳的警告!它仍然可以工作,但每个文档需要单独的往返。在2.6+中,驱动程序在一次往返中将整个操作发送到服务器,服务器报告成功的次数和失败次数。