所有失败的 bulkWrite 操作都会在返回文档的数组中报告,以及插入失败的完整文档。例如,这段代码通过java驱动:
MongoCollection<Document> collection = database.getCollection("bulk");
List<WriteModel<Document>> writes = new ArrayList<WriteModel<Document>>();
writes.add(new InsertOneModel<Document>(new Document("_id", 1)));
writes.add(new InsertOneModel<Document>(new Document("_id", 2)));
writes.add(new InsertOneModel<Document>(new Document("_id", 2)));
writes.add(new InsertOneModel<Document>(new Document("_id", 4)));
BulkWriteResult bulkWriteResult = collection.bulkWrite(writes);
System.out.println(bulkWriteResult.toString());
返回这个:
Exception in thread "main" com.mongodb.MongoBulkWriteException:
Bulk write operation error on server localhost:27017. Write errors:
[BulkWriteError{index=2, code=11000, message='E11000 duplicate key
error collection: test.bulk index: _id_ dup key: { : 2 }',
details={ }}].
您没有提及您使用的是哪个版本的 MongoDB,但如果您想进一步了解,这里是无序 bulkWrites 的 3.2 版手动条目:https://docs.mongodb.org/manual/core/bulk-write-operations/。
但是,如果您所说的“异常”是指在加载操作过程中客户端或 mongod 进程崩溃,或者发生硬件或网络事件,则不会有从 bulkWrite 干净退出,因此没有 bulkWriteResult输出如上。无序bulkWrites并行执行操作,不一定按输入顺序执行,分片集合和分布式集群更复杂,因此无法准确知道崩溃前完成了哪些操作。唯一的解决方案是重复整个工作,这通常需要您删除所有第一次成功插入的文档。
如果您正在加载到一个新的或空的集合,您可以简单地删除并重新创建它。如果有一个带有索引的唯一键,您可以重复加载,因为第一次插入 OK 的文档将作为重复文件被拒绝。否则,您将不得不运行清理作业以删除所有可能/应该在开始重新加载尝试之前插入的文档,如果它们不容易识别,则可能会出现问题。
此方案的最佳方法是将大型加载操作分解为更小的部分,因此您有四个加载作业,每个作业包含四分之一的数据(或二十个每个包含 5% 的数据,依此类推)。以这种方式设计加载过程需要付出更多的努力,但使用 5% 的总数据重复一项作业比必须重复一个在 95% 标记处失败的加载要快得多。
如果为每个作业添加不同值的 loadNum 字段,则可以使用 count(“loadNum”:n) 来确认所有文档已加载,而 remove(“loadNum”:n) 将删除仅部分成功的作业中的所有文档。