LeM*_*Miz 126 python bulkinsert mongodb mongodb-query
每天,我收到一份文件(更新).我想要做的是插入每个尚不存在的项目.
我正在使用Python驱动程序(pymongo).
我目前做的是(伪代码):
for each document in update:
existing_document = collection.find_one(document)
if not existing_document:
document['insertion_date'] = now
else:
document = existing_document
document['last_update_date'] = now
my_collection.save(document)
Run Code Online (Sandbox Code Playgroud)
我的问题是它非常慢(少于100 000条记录需要40分钟,而且我在更新中有数百万条记录).我很确定有内置的东西可以做到这一点,但更新()的文件是mmmhhh ....有点简洁....(http://www.mongodb.org/display/DOCS/Updating)
有人可以建议如何更快地做到这一点?
Van*_*yen 135
听起来你想做一个"upsert".MongoDB内置了对此的支持.将额外参数传递给update()调用:{upsert:true}.例如:
key = {'key':'value'}
data = {'key2':'value2', 'key3':'value3'};
coll.update(key, data, upsert=True); #In python upsert must be passed as a keyword argument
Run Code Online (Sandbox Code Playgroud)
这将完全取代您的if-find-else-update块.如果密钥不存在,它将插入,如果密钥不存在则会更新.
之前:
{"key":"value", "key2":"Ohai."}
Run Code Online (Sandbox Code Playgroud)
后:
{"key":"value", "key2":"value2", "key3":"value3"}
Run Code Online (Sandbox Code Playgroud)
您还可以指定要写入的数据:
data = {"$set":{"key2":"value2"}}
Run Code Online (Sandbox Code Playgroud)
现在,您选择的文档将仅更新"key2"的值,并保持其他所有内容不变.
and*_*ndy 52
从MongoDB 2.4开始,你可以使用$ setOnInsert(http://docs.mongodb.org/manual/reference/operator/setOnInsert/)
使用$ setOnInsert设置'insertion_date',使用upsert命令中的$ set设置'last_update_date'.
要将您的伪代码转换为一个工作示例:
now = datetime.utcnow()
for document in update:
collection.update_one(
{"_id": document["_id"]},
{
"$setOnInsert": {"insertion_date": now},
"$set": {"last_update_date": now},
},
upsert=True,
)
Run Code Online (Sandbox Code Playgroud)
Ram*_*ony 15
您总是可以创建一个唯一索引,这会导致MongoDB拒绝冲突的保存.考虑使用mongodb shell完成以下操作:
> db.getCollection("test").insert ({a:1, b:2, c:3})
> db.getCollection("test").find()
{ "_id" : ObjectId("50c8e35adde18a44f284e7ac"), "a" : 1, "b" : 2, "c" : 3 }
> db.getCollection("test").ensureIndex ({"a" : 1}, {unique: true})
> db.getCollection("test").insert({a:2, b:12, c:13}) # This works
> db.getCollection("test").insert({a:1, b:12, c:13}) # This fails
E11000 duplicate key error index: foo.test.$a_1 dup key: { : 1.0 }
Run Code Online (Sandbox Code Playgroud)
Yul*_*ney 11
您可以使用Upsert和$ setOnInsert运算符.
db.Table.update({noExist: true}, {"$setOnInsert": {xxxYourDocumentxxx}}, {upsert: true})
Run Code Online (Sandbox Code Playgroud)
小智 6
根据Van Nguyen的上述答案,使用更新而不是保存.这使您可以访问upsert选项.
注意:此方法在找到时覆盖整个文档(来自文档)
var conditions = { name: 'borne' } , update = { $inc: { visits: 1 }} , options = { multi: true };
Model.update(conditions, update, options, callback);
function callback (err, numAffected) { // numAffected is the number of updated documents })
Run Code Online (Sandbox Code Playgroud)
如果要更新文档的选择而不是整个文档,可以使用$ set方法和update.(再次,来自文档)...所以,如果你想设置......
var query = { name: 'borne' }; Model.update(query, ***{ name: 'jason borne' }***, options, callback)
Run Code Online (Sandbox Code Playgroud)
发送给...
Model.update(query, ***{ $set: { name: 'jason borne' }}***, options, callback)
Run Code Online (Sandbox Code Playgroud)
这有助于防止意外覆盖您的所有文档{ name: 'jason borne' }.
小智 5
我不认为mongodb支持这种类型的选择性upserting.我和LeMiz有同样的问题,并且在处理'created'和'updated'时间戳时,使用update(criteria,newObj,upsert,multi)不起作用.鉴于以下upsert声明:
update( { "name": "abc" },
{ $set: { "created": "2010-07-14 11:11:11",
"updated": "2010-07-14 11:11:11" }},
true, true )
Run Code Online (Sandbox Code Playgroud)
场景#1 - 'name'为'abc'的文档不存在:使用'name'='abc'创建新文档,'created'= 2010-07-14 11:11:11,'updated'= 2010-07-14 11:11:11
场景#2 - 'name'为'abc'的文档已经存在以下内容:'name'='abc','created'= 2010-07-12 09:09:09,'updated'= 2010-07 -13 10:10:10 在upsert之后,文档现在将与场景#1中的结果相同.如果插入,则无法在upsert中指定要设置的字段,如果更新,则不保留哪些字段.
我的解决方案是在critera字段上创建一个唯一索引,执行插入,然后立即在'updated'字段上执行更新.
摘要
注意,我假设PyMongo,改为适合您选择的语言.
说明:
使用unique = true的索引创建集合,这样您就不会获得重复记录.
迭代输入记录,创建大约15,000条记录的批次.对于批处理中的每个记录,创建一个由要插入的数据组成的字典,假设每个记录都是新记录.将"已创建"和"已更新"时间戳添加到这些时间戳.将此问题作为带有'ContinueOnError'标志= true的批量插入命令发出,因此即使其中存在重复键(它听起来会有),也会发生其他所有内容的插入.这将非常快.批量插入摇滚,我获得了15k /秒的性能水平.有关ContinueOnError的更多说明,请参阅http://docs.mongodb.org/manual/core/write-operations/
记录插入非常快,因此您可以立即完成这些插入操作.现在,是时候更新相关记录了.通过批量检索执行此操作,比一次快一个.
再次迭代所有输入记录,创建15K左右的批次.提取密钥(如果有一个密钥,则最好,但如果没有,则无法帮助).使用db.collectionNameBlah.find({field:{$ in:[1,2,3 ...})查询从Mongo检索这一组记录.对于每个记录,确定是否有更新,如果是,则发出更新,包括更新"更新的"时间戳.
不幸的是,我们应该注意,MongoDB 2.4及更低版本不包含批量更新操作.他们正在努力.
关键优化点:
| 归档时间: |
|
| 查看次数: |
129400 次 |
| 最近记录: |