2015-07-13 58 views
3

我正在更新一个数据库,其中有几百万个文档,其中包含少于10个_id冲突。有没有办法在Pymongo 3.0中跳过insert_many的现有_id?

我目前使用的PyMongo模块做使用insert_many通过批量插入:

  1. 查询数据库,看是否存在_id
  2. 然后添加文件到一个数组,如果_id不存在
  3. 使用insert_many插入数据库,每次1000个文档。

在几百万个文档中只有大约10个冲突,而且我正在查询每个_id的数据库。我认为如果我能削减查询过程,我可以减少一两天的整体插入时间。

有没有类似于upsert的东西,也许只有插入一个文件,如果它不存在?

回答

6

更好的方式来处理这个问题,也有“插入/更新”许多文件以有效的方式是使用Bulk Operations API提交的所有信息在“批”与所有的effecient发送和接收的“奇回应”确认。

这可以通过两种方式处理。

首先忽略主键或其他指标的任何“重复错误”,那么你可以使用“无序”的形式操作:

bulk = pymongo.bulk.BulkOperationBuilder(collection,ordered=False) 
for doc in docs: 
    bulk.insert(doc) 

response = bulk.execute() 

的“无序”或false说法存在,使得运营都可以以任何顺序执行,并且“完整”批处理将完成,只是在响应中“报告”任何实际错误。所以这是一种基本上“忽略”重复和移动的方法。

的另一种方法是大致相同,但使用与$setOnInsert沿着“更新插入”功能性:

bulk = pymongo.bulk.BulkOperationBuilder(collection,ordered=True) 
for doc in docs: 
    bulk.find({ "_id": doc["_id"] }).upsert().updateOne({ 
     "$setOnInsert": doc 
    }) 

response = bulk.execute() 

由此.find()“查询”部分用于查询为一个文件,使用存在的“主键“或备选地文档的”唯一键“。如果找不到匹配,则在创建新文档时会出现“upsert”。由于所有修改内容都在$setOnInsert之内,因此只有在发生“upsert”时才会修改文档字段。否则,在文件“匹配”的情况下,对于保存在该操作员下的数据,实际上没有任何变化。

在这种情况下,“有序”意味着每个语句实际上是以它创建的“相同”顺序提交的。此外,任何“错误”都会停止更新(在发生错误的位置),以便没有更多的操作会被执行。它是可选的,但可能建议用于正常的“重复”行为,其中后面的语句“复制”前一个数据。

因此,为了更有效的写入,总体思路是使用“Bulk”API并相应地构建您的操作。这里的选择实际上取决于来源的“插入顺序”是否对您很重要。

当然,"ordered"=False操作适用于insert_many,它实际上在较新的驱动程序版本中使用“批量”操作。但通过使用简单的API可以“混合”操作的通用界面,您将获得更大的灵活性。

+0

Gotcha。因此,使用带有“ordered”= False的insert_many将继续运行所有插入,而忽略可能弹出的任何错误? – SLee

+1

@SLee它应该。有些API已被“修改”,所以结果实际上会引发异常(以前不是这种情况),但“整个”批处理应该执行。另一方面,“upsert”选项不能抛出异常(来自重复键),因为它并不意味着它的任何操作错误。正如我所说,*“关键在于操作顺序是否重要”*。 –

相关问题