【问题标题】:How to compare all documents in two collections with millions of doc and write the diff in a third collection in MongoDB如何将两个集合中的所有文档与数百万个文档进行比较,并将差异写入 MongoDB 的第三个集合中
【发布时间】:2017-07-02 04:42:10
【问题描述】:

我有两个集合(coll_1,coll_2),每个集合有一百万个文档。

这两个集合实际上是通过运行来自同一数据源的两个版本的代码创建的,因此两个集合将具有相同数量的文档,但两个集合中的文档可能缺少一个字段或子文档,或者具有不同的值,但两个集合的文档将具有相同的 primary_key_id,它被编入索引。

我在数据库中保存了这个 javascript 函数来获取差异

db.system.js.save({
    _id: "diffJSON", value:
    function(obj1, obj2) {
        var result = {};
        for (key in obj1) {
            if (obj2[key] != obj1[key]) result[key] = obj2[key];
            if (typeof obj2[key] == 'array' && typeof obj1[key] == 'array')
                result[key] = arguments.callee(obj1[key], obj2[key]);
            if (typeof obj2[key] == 'object' && typeof obj1[key] == 'object')
                result[key] = arguments.callee(obj1[key], obj2[key]);
        }
        return result;
    }
});

这样运行良好

diffJSON(testObj1, testObj2);

问题:如何在 coll1 和 coll2 上运行 diffJSON,并将 diffJSON 结果与 primary_key_id 一起输出到 coll3。

我是 MongoDB 新手,我知道 JOINS 的工作方式与 RDBMS 不同,所以我想知道是否必须将两个比较文档复制到一个集合中,然后运行 ​​diffJSON 函数。

另外,大多数时候(比如 90%)两个集合中的文档是相同的,我只需要知道大约 10% 的文档有任何差异。

这是一个简单的示例文档: (但真正的文档大小约为 15k,只是让您知道规模)

var testObj1 = { test:"1",test1: "2", tt:["td","ax"], tr:["Positive"] ,tft:{test:["a"]}};
var testObj2 = { test:"1",test1: "2", tt:["td","ax"], tr:["Negative"] };

如果您知道比较文档的更好方法,请随时提出建议。

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    您可以使用一个简单的 shell 脚本来实现这一点。首先创建一个名为script.js 的文件并将此代码粘贴到其中:

    // load previously saved diffJSON() function
    db.loadServerScripts();
    
    // get all the document from collection coll1
    var cursor = db.coll1.find(); 
    
    if (cursor != null && cursor.hasNext()) {
      // iterate over the cursor 
      while (cursor.hasNext()){
       var doc1 = cursor.next();
       // get the doc with the same _id from coll2 
       var id = doc1._id; 
       var doc2 = db.coll2.findOne({_id: id});
       // compute the diff 
       var diff = diffJSON(doc2, doc1);
       // if there is a difference between the two objects
       if ( Object.keys(diff).length > 0 ) {
         diff._id = id;
         // insert the diff in coll3 with the same _id
         db.coll3.insert(diff);
       }
      }
    }
    

    在此脚本中,我假设您的 primary_key_id 字段。

    然后像这样从你的 shell 执行它:

    mongo --host hostName --port portNumber databaseName < script.js
    

    其中databaseName 是包含集合coll1coll2 的数据库的来源。

    对于这个示例文档(刚刚在您的文档中添加了一个 _id 字段):

    var testObj1 = { _id: 1, test:"1",test1: "2", tt:["td","ax"], tr:["Positive"] ,tft:{test:["a"]}};
    var testObj2 = { _id: 1, test:"1",test1: "2", tt:["td","ax"], tr:["Negative"] };
    

    脚本会将以下文档保存在coll3 中:

     { "_id" : 1, "tt" : {  }, "tr" : { "0" : "Positive" } }
    

    【讨论】:

      【解决方案2】:

      此解决方案基于 felix 提出的解决方案(我没有必要的声誉来评论他的)。我对他的脚本做了一些小的改动,带来了重要的性能改进:

      // load previously saved diffJSON() function
      db.loadServerScripts();
      
      // get all the document from collection coll1 and coll2
      var cursor1 = db.coll1.find().sort({'_id': 1});
      var cursor2 = db.coll2.find().sort({'_id': 1});
      
      if (cursor1 != null && cursor1.hasNext() && cursor2 != null && cursor2.hasNext()) {
        // iterate over the cursor
        while (cursor1.hasNext() && cursor2.hasNext()){
         var doc1 = cursor1.next();
         var doc2 = cursor2.next();
         var pk = doc1._id
         // compute the diff
         var diff = diffJSON(doc2, doc1);
         // if there is a difference between the two objects
      
         if ( Object.keys(diff).length > 0 ) {
           diff._id = pk;
           // insert the diff in coll3 with the same _id
           db.coll3.insert(diff);
         }
        }
      }
      

      两个游标用于获取数据库中按主键排序的所有条目。这是一个非常重要的方面,并带来了大部分的性能改进。通过检索按主键排序的文档,我们确保我们通过主键正确匹配它们。这是基于两个集合拥有相同数据的事实。

      这样我们可以避免为 coll1 中的每个文档调用 coll2。这可能看起来微不足道,但我们谈论的是 100 万次调用,这给数据库带来了很大压力。

      另一个重要的假设是主键字段是_id。如果不是这种情况,那么在主键字段上有一个唯一索引至关重要。否则,脚本可能会与具有相同主键的文档不匹配。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-23
        • 1970-01-01
        • 2017-08-16
        • 2015-09-25
        • 2011-12-07
        • 2016-02-22
        • 2016-09-22
        相关资源
        最近更新 更多