Ruby MongodB—提高处理多个集合的速度
我正在使用MongoDB和Ruby,使用Ruby MongodB—提高处理多个集合的速度,ruby,mongodb,Ruby,Mongodb,我正在使用MongoDB和Ruby,使用mongogem 我有以下情况: 对于集合中的每个文档,例如coll1,请查看key1和key2 搜索另一个集合中的文档,例如coll2,其中包含key1和key2 如果存在匹配项,则在#1中引用的文档中添加在#2中获取的文档,并使用新键key3,其值应设置为key3 将更新的哈希插入新集合coll3 MongoDB的一般指导原则是在应用程序代码中处理交叉收集操作 因此,我做了以下工作: client = Mongo::Client.new([ '
mongo
gem
我有以下情况:
coll1
,请查看key1
和key2
coll2
,其中包含key1
和key2
key3
,其值应设置为key3
coll3
client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => some_db,
:server_selection_timeout => 5)
cursor = client[:coll1].find({}, { :projection => {:_id => 0} }) # exclude _id
cursor.each do |doc|
doc_coll2 = client[:coll2].find('$and' => [{:key1 => doc[:key1]}, {:key2 => doc[:key2] }]).limit(1).first # no find_one method
if(doc_coll2 && doc[:key3])
doc_coll2[:key3] = doc[:key3]
doc_coll2.delete(:_id) # remove key :_id
client[:coll3].insert_one(doc_coll2)
end
end
这是可行的,但完成这项工作需要很多时间——在collectioncoll1
中,每个文档大约需要250毫秒,或者大约15000条记录需要3600秒(1小时),这似乎是一个很大的工作量,可能与一次读取一个文档、执行签入应用程序代码,然后一次写入一个文档返回到新的集合有关
有没有办法让这项工作做得更快?我现在的做法是正确的吗
示例文档
- coll1
{ "_id" : ObjectId("588610ead0ae360cb815e55f"), "key1" : "115384042", "key2" : "276209", "key3" : "10101122317876" }
- coll2
{ "_id" : ObjectId("788610ead0ae360def15e88e"), "key1" : "115384042", "key2" : "276209", "key4" : 10, "key5" : 4, "key6" : 0, "key7" : "false", "key8" : 0, "key9" : "false" }
- coll3
{ "_id" : ObjectId("788610ead0ae360def15e88e"), "key1" : "115384042", "key2" : "276209", "key3" : "10101122317876", "key4" : 10, "key5" : 4, "key6" : 0, "key7" : "false", "key8" : 0, "key9" : "false" }
- 使用
$lookup
- 使用
$unwind
- 使用
$redact
- 使用
$project
- 用
$out
- 解决方案是使用聚合,并在一个查询中执行此操作:
db.coll1.aggregate([
{ "$lookup": {
"from": "coll2",
"localField": "key1",
"foreignField": "key1",
"as": "coll2_doc"
}},
{ "$unwind": "$coll2_doc" },
{ "$redact": {
"$cond": [
{ "$eq": [ "$key2", "$coll2_doc.key2" ] },
"$$KEEP",
"$$PRUNE"
]
}},
{
$project: {
key1: 1,
key2: 1,
key3: 1,
key4: "$coll2_doc.key4",
key5: "$coll2_doc.key5",
key6: "$coll2_doc.key6",
key7: "$coll2_doc.key7",
key8: "$coll2_doc.key8",
key9: "$coll2_doc.key9",
}
},
{$out: "coll3"}
], {allowDiskUse: true} );
而db.coll3.find()
将返回
{
"_id" : ObjectId("588610ead0ae360cb815e55f"),
"key1" : "115384042",
"key2" : "276209",
"key3" : "10101122317876",
"key4" : 10,
"key5" : 4,
"key6" : 0,
"key7" : "false",
"key8" : 0,
"key9" : "false"
}
编辑:MongoDB 3.4解决方案
如果不想在$project
阶段指定所有键,可以利用MongoDB 3.4中引入的两个新操作符$addFields
和$replaceRoot
查询将变成:
db.coll1.aggregate([
{ "$lookup": {
"from": "coll2",
"localField": "key1",
"foreignField": "key1",
"as": "coll2_doc"
}},
{ "$unwind": "$coll2_doc" },
{ "$redact": {
"$cond": [
{ "$eq": [ "$key2", "$coll2_doc.key2" ] },
"$$KEEP",
"$$PRUNE"
]
}},
{$addFields: {"coll2_doc.key3": "$key3" }},
{$replaceRoot: {newRoot: "$coll2_doc"}},
{$out: "coll3"}
], {allowDiskUse: true})
在考虑了一段时间后,他意识到索引并没有被添加。添加索引可以将查询运行时间减少几个数量级 要添加索引,请执行以下操作
db.coll1.ensureIndex({"key1": 1, "key2": 1});
db.coll2.ensureIndex({"key1": 1, "key2": 1});
使用索引,整个查询运行时间是之前的1/10xxxxxx倍
学习内容是,在处理大型数据集时,为
find
使用的字段编制索引,这本身就大大减少了查询运行时间。您能否提供coll1和coll2中的示例文档,以及预期结果的示例(要插入coll3中的文档)?为coll1添加了示例,coll2和coll3在$project:
聚合的一部分中,我需要coll2
中的所有键,加上coll1
中的key3
-有没有一种方法比必须指定coll2中的所有键更简单的方法来指定这一点-该集合有200个键:(我试过了,这很有效。但是关于速度的提高,我观察到的改进是,使用应用程序代码时,每小时15000个coll1文档,使用mongoDb aggregate时,每小时37000个coll1文档。这是否超出了预期范围,还是花费的时间太长?对我来说,与典型的RDBMS相比,这要长一个数量级。)就完成时间而言。@user3206440您提供的信息无法回答。这在很大程度上取决于您使用的硬件(磁盘类型、RAM…)还有你的收集内容。你应该看一下查询的结果,更好地了解发生了什么。了解你的观点,但是,在同一台机器上,性能数字是否与预期一致?