Ruby MongoDB - 提高处理多个集合时的速度

标签 ruby mongodb

我使用 mongo gem 将 MongoDB 与 Ruby 结合使用。

我有以下场景:

  1. 对于集合中的每个文档说 coll1,查看 key1key2
  2. 在另一个集合中搜索文档,比如 coll2 以及 key1key2 的匹配值
  3. 如果匹配,则使用新键 key3 添加在 #2 中获取的文档,其值设置为 #1< 中引用的文档中 key3 的值/li>
  4. 将更新后的散列插入新集合 coll3

MongoDB 的一般准则是在应用程序代码中处理交叉集合操作。

所以我做了以下事情:

    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

这行得通,但是完成这项工作需要很多时间——集合 coll1 中的每个文档大约需要 250 毫秒,或者大约 15000 条记录需要 3600 秒(1 小时),这看起来很多,这可能与一次阅读一个文档相关联,检查应用程序代码,然后一次将一个文档写回新集合。

有没有办法更快地完成此操作?我的做法是否正确?

示例文档

  • col1

    {
        "_id" : ObjectId("588610ead0ae360cb815e55f"),
        "key1" : "115384042",
        "key2" : "276209",
        "key3" : "10101122317876"
    }
    
  • col2

    {
        "_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 对 key1 字段执行连接
  • 使用$unwind展开数组
  • 使用 $redactcoll1.key2 == coll2.key2 处保存文档
  • $project重新格式化文档
  • $out 把它写到coll3

所以查询将是:

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阶段指定所有键,你可以利用$addFields$replaceRoot , MongoDB 3.4 中引入的两个新运算符

查询将变为:

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})

关于Ruby MongoDB - 提高处理多个集合时的速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41993703/

相关文章:

ruby - 如何使用 telnet 从远程嵌入式系统获取二进制文件?

ruby - class << Ruby 中的 self 习语

node.js - 使用 systemd 连接到 MongoDB,在 Linux (Debian) 上托管 Meteor (MeteorJS)。错误 : URL must be in the format mongodb://user:pass@host:port/dbname

ruby - 我可以通过 http 下载名称中包含空格的文件吗? ( ruby )

ruby - 如何有效地从哈希的哈希中提取具有特定键名的所有值?

java - Mongodb通过java中的嵌套字段搜索

mongodb - 将数组字段中的每个 ObjectId 解析为另一个集合中的对象

javascript - Jade/Mongo 输出中的换行符

javascript - Mongoose 与 mongodb 如何返回刚刚保存的对象?

ruby-on-rails - 带分页功能的 Google 自定义搜索 API