避免MongoDB批量插入重复键错误

17
我该如何执行批量插入并在出现重复键错误时继续进行?
我有一个带有唯一索引的集合,索引是在id字段(而非_id)上建立的,并且其中包含一些数据。然后我获取了更多数据,只想将不存在的文档添加到集合中。
我有以下代码:
let opts = {
  continueOnError: true, // Neither
  ContinueOnError: true, // of
  keepGoing: true,       // this
  KeepGoing: true,       // works
};
let bulk = collection.initializeUnorderedBulkOp( opts );
bulk.insert( d1 );
bulk.insert( d2 );
bulk.insert( d3 );
...
bulk.insert( dN );
let result = yield bulk.execute( opts ); // this keep throwing duplicate key error

我只想忽略错误,让批量操作完成所有排队的操作。
我在npm模块API和MongoDB API中搜索Bulk, initializeUnorderedBulkOp以及Bulk write的文档,但没有找到。

在无序操作文档中,他们

错误处理

如果在处理其中一个写操作时发生错误,MongoDB将继续处理列表中剩余的写操作。

这是不正确的(至少在我的情况下)。


这是具有误导性的,而且最近的版本中错误情况实际上已经改变了,因为以前的 UnOrderdedBukOp 结构永远不会产生“抛出”错误,而只会在响应中产生“错误列表”。不是第一个对此抱怨的人。一般的建议是“忽略”错误并自己检查结果对象,因为结果将始终继续到批处理的末尾。所以你的说法是不正确的,因为它实际上确实写入了列表中的所有操作(有效的操作),但它只是在我认为不应该抛出一个错误。 - Blakes Seven
谢谢您的澄清,但我的问题是使用 promises 的 execute 方法会引发异常,并且承诺只会被拒绝并失去 BulkWriteResult 对象。 - Volox
1
是的。这正是我的回答。以前的驱动程序在这种情况下没有引发异常,现在它们会这样做。然而,这对“UnOrdered”操作的处理方式没有影响。批处理仍然作为一个整体执行,但是,与其只在响应对象中返回“错误”,结果会“抛出”错误,因为至少发生了一个错误。现在明白了吗? - Blakes Seven
你可以使用bulk.find().upsert().replaceOne()来代替insert。这样,如果找到了具有该id的文档,则将其替换为新文档,否则将创建一个新文档。没有重复键错误,状态一致。 - Markus W Mahlberg
2个回答

11

1
它实际上与重复数据错误无关。正如其名称和手册所述,它的作用是“指定mongod实例是否应执行有序或无序插入的布尔值”。 - SET001
3
在文档的同一页上,你可以找到以下内容:"If ordered to false, the insert operation would continue with any remaining documents."(如果设置为false,插入操作将继续处理任何剩余的文档。)和"Excluding Write Concern errors, ordered operations stop after an error, while unordered operations continue to process any remaining write operations in the queue. Ordered operations display the single error encountered while unordered operations display each error in an array. Therefore, with this strange setting (ordered:false) you will continue to process remaining write operations in the list."(除了写关注错误外,有序操作在发生错误后停止,而无序操作会继续处理队列中的任何剩余写操作。有序操作显示遇到的单个错误,而无序操作则以数组形式显示每个错误。因此,使用这种奇怪的设置(ordered:false),你将继续处理列表中的剩余写操作。) - Stanislav Prusac

8

MongoDB中的有序插入

db.hobbies.insertMany([{_id: "yoga", name: "Yoga"}, {_id: "cooking", name: "Cooking"}, {_id: "hiking", name: "Hiking"}], {ordered: true})

{ordered: true} 是插入语句的默认行为。

MongoDB 中的无序插入

如果您希望 MongoDB 在遇到某个文档插入失败后仍然继续尝试插入其他文档,您必须将 ordered 设置为 false。请参见以下示例:

db.hobbies.insertMany([{_id: "yoga", name: "Yoga"}, {_id: "cooking", name: "Cooking"}, {_id: "hiking", name: "Hiking"}], {ordered: false})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接