MongoDB批量插入许多文件已经存在的地方

我有一个较小的文档(大约100个),可以插入到MongoDB中。 但是他们中的许多人(可能全部,但通常是80%左右)将已经存在于DB中。 这些文档代表未来几个月即将发生的事件,而且我每两天更新一次数据库。 所以大部分事件已经在那里了。

任何人都知道(或者想猜)是否会更有效率地:

  1. 做批量更新,但与continueOnError = true,例如

db.collection.insert(myArray, {continueOnError: true}, callback)

  1. 做单独的插入,首先检查_ID是否存在?

  2. 首先做一个大的删除(像db.collection.delete({_id: $in : [array of all the IDs in my new documents] }) ,然后批量插入?

我可能会做#1,因为这是最简单的,我不认为100个文件都很大,所以它可能没关系,但如果有10,000个文件? 如果有问题,我使用node.js驱动程序在JavaScript中执行此操作。 我的背景是在Java中,exception很耗时,这就是我所要求的主要原因 – “continueOnError”选项会耗时吗?

补充:我不认为“upsert”是有道理的。 这是为了更新单个文件。 就我而言,代表即将到来的事件的单个文件没有改变。 (好吧,也许是这是另一个问题)

发生了什么是一些新的文件将被添加。

我的背景是在Java中,exception很耗时,这就是我所要求的主要原因 – “continueOnError”选项会耗时吗?

批量插入的ContinueOnError标志仅影响批处理的行为:不是在遇到第一个错误时停止处理,将处理完整批处理。

在MongoDB 2.4中,你只会得到一个错误的批处理,这将是最后遇到的错误。 这意味着如果你关心捕捉错误,你会更好地做个别插入。

大块插入与单插入的主要时间节省是减lessnetworking往返。 驱动程序可以将批量插入分为多达批量的最多由mongod服务器(当前为48Mb)接受的MaxMessageSizeBytes ,而不是向每个文档发送消息到MongoDB服务器。

批量插入是否适合此用例?

如果你只用了100个(甚至1000个)文档来插入已经存在80%的文档,那么使用批量插入(特别是如果这个过程每隔几天就会发生一次)可能没有什么好处。 您的小插入将分批进行组合,但80%的文档实际上并不需要发送到服务器。

我仍然倾向于使用ContinueOnError来批量插入删除和重新插入的方法,但是批量插入可能是一个不必要的早期优化,因为您正在使用的文档的数量和实际需要插入的百分比。

我会build议用不同的方法做几次运行,看看实际的影响是怎样的。

MongoDB 2.6

作为首席,MongoDB 2.5开发系列中的批处理function正在得到显着改善(这将在2.6版本的发布中达到高潮)。 计划的function包括支持批量插入和累积每文档错误,而不是每批错误。

新的写入命令将要求驱动程序更改支持,但可能会改变上面的一些假设。 例如,对于使用新的批处理API的ContinueOnError ,最终可能会得到80%的批处理ID是重复键的结果。

有关更多详细信息,请参阅MongoDB问题跟踪器中的父问题SERVER-9038 。

 collection.insert(item, {continueOnError: true, safe: true}, function(err, result) { if (err && err.code != "11000"){ throw err; } db.close(); callBack(); }); 

我会保证使用upsert让mongo处理更新或插入逻辑,您也可以使用multi来更新符合条件的多个文档:

从文档:

upsert可选参数(如果设置为true)在没有文档匹配查询条件时创build一个新文档。 默认值为false,当找不到匹配项时不插入新文档。 这个参数的语法取决于MongoDB的版本。 请参阅Upsert参数 。

可选参数(如果设置为true)会更新符合查询条件的多个文档。 如果设置为false,则更新一个文档。 默认值是false。 有关其他信息, 请参阅多参数。

 db.collection.update( <query>, <update>, { upsert: <boolean>, multi: <boolean> } ) 

这里是引用的文档: http : //docs.mongodb.org/manual/reference/method/db.collection.update/

对于你的情况,我build议你考虑获取现有文档列表_id s,然后只发送不在该列表中的文档已经。 虽然你可以用upsert更新来单独更新,但没有什么理由这样做。 除非_id列表非常长(数以万计),否则抓取列表并进行比较会比单独更新每个文档的数据库更有效率(某些大比例显然未能更新)。

我不会使用continueOnError并发送所有文档…效率不高。