【问题标题】:Compare a mongo diff on two collections比较两个集合的 mongo 差异
【发布时间】:2017-05-04 12:25:13
【问题描述】:

我有两个 mongo 集合,一个是指生产环境,另一个是测试环境。

如何比较我的两个集合之间的差异?

我尝试将它们转储到 bson,然后转换为 json。但我不能只对它们进行简单的比较,因为排序可能会有所不同,而且 json 文件太大而无法排序。

【问题讨论】:

    标签: mongodb collections diff


    【解决方案1】:

    在 shell 中尝试以下操作,它将遍历集合中的每个项目并尝试根据 ID 匹配每个文档。

    假设我们有 2 个集合 db.col1db.col2

    > db.col1.find()
    { "_id" : 1, "item" : 1 }
    { "_id" : 2, "item" : 2 }
    { "_id" : 3, "item" : 3 }
    { "_id" : 4, "item" : 4 }
    
    > db.col2.find()
    { "_id" : 1, "item" : 1 }
    { "_id" : 2, "item" : 2 }
    { "_id" : 3, "item" : 3 }
    { "_id" : 4, "item" : 4 }
    

    然后我们可以创建一个 javascript 函数来比较 2 个集合

    function compareCollection(col1, col2){
        if(col1.count() !== col2.count()){
            return false;
        }
    
        var same = true;
    
        var compared = col1.find().forEach(function(doc1){
            var doc2 = col2.findOne({_id: doc1._id});
    
            same = same && JSON.stringify(doc1)==JSON.stringify(doc2);
        });
    
        return same;
    }
    

    然后调用如下:

    > compareCollection(db.col1, db.col2)
    true
    

    如果我们有第三个集合db.col3

    > db.col3.find()
    { "_id" : 1, "item" : 1 }
    

    比较一下这个

    > compareCollection(db.col1, db.col3)
    false
    

    我们会得到预期的结果。

    如果我们还有第 4 个集合,它有匹配的文档但不同的数据 db.col4

    > db.col4.find()
    { "_id" : 1, "item" : 10 }
    { "_id" : 2, "item" : 2 }
    { "_id" : 3, "item" : 3 }
    { "_id" : 4, "item" : 4 }
    

    这也将返回false

    > compareCollection(db.col1, db.col4)
    false
    

    【讨论】:

    • 如果我有 500 万条记录怎么办?这不会导致一些性能问题吗?没有更直接的方法吗?
    • 如果您有 500 万条记录...比较它们的唯一方法是检查所有 500 万条记录,我想如果您的文档中有其他内容使它们独一无二,您可以与之进行比较并将其作为索引,但是如果您需要检查它们是否匹配,则需要检查它们是否匹配?
    • Mingo.io 有一个功能可以满足您的需求。
    【解决方案2】:

    如果您只需要比较字段的子集(例如,您不需要比较 id),您可以通过以下方式进行。将集合导出到 csv,指定要比较的字段 (source):

    mongoexport -d <db_name> -c <col_name> --fields "field1,field2" --type=csv | sort > export.csv
    

    然后对 csv 文件执行简单的diff。请注意,csv 文件中的列顺序对应于--field 选项。

    优点:

    • 您可以指定要比较的字段子集。
    • 您可以看到记录的实际差异。

    缺点:

    • 要比较完整记录,您需要了解所有可能的字段。
    • mongoexport 对于大型数据库可能会很慢。

    要获取集合中所有文档的所有字段,请参阅this answer

    【讨论】:

      【解决方案3】:

      使用 Studio 3T 对比 mongodb。 您也可以比较集合、数据库、单个记录。 只需要下载并连接mongo。 这是下载链接https://studio3t.com/

      【讨论】:

      • 也许您可以在一些教程中添加一些链接,了解如何在该特定工具中进行操作。
      • 特别是因为此功能不是免费版的一部分(甚至不是“廉价”许可证),而只是企业版...如果有人确实有这个工具,这里是实战教程链接:studio3t.com/whats-new/diff-mongodb/…
      【解决方案4】:

      dbHash 成功了:

      use db_name
      db.runCommand('dbHash')
      

      它返回每个集合的哈希值。然后,您可以比较它们。非常准确。

      【讨论】:

      • 它没有为具有相同数据的两个集合返回相同的哈希值。
      • _id 总会导致 hash mismtach
      【解决方案5】:

      使用Kevin Smith response,我有一个新版本,仅用于比较并返回collectionB 没有与collectionA 比较的那些ID。当您有很多记录时,将结果保存在collectionC 中。

          db.collectionA.find().forEach(function(doc1){
              var doc2 = db.collectionB.findOne({_id: doc1._id});
              if (!(doc2)) {
                      db.collectionC.insert(doc1);
              }
          });
      

      【讨论】:

      • 这是最好、最简洁的答案,谢谢卡洛斯。注意:在比较两个文档时,我必须先删除 doc1.__vdoc2.__v,然后再对它们进行字符串化。
      • @chichilatte 你是如何删除变量的?
      • @Mallik 只是在 forEach 回调函数中添加了类似delete doc1.__v 的行
      【解决方案6】:

      mongoexport 现在有一个--sort 选项:

      例如:

      $ mongo
      test> db.coll.insertMany([
        { _id: 0, name: 'Alex' },
        { _id: 1, name: 'Bart' },
        { _id: 2, name: 'Maria' },
        { _id: 3, name: 'Aristotle' },
      ]);
      {
        "acknowledged": true,
        "insertedIds": [
          0,
          1,
          2,
          3
        ]
      }
      

      导出:

      mongoexport -d test -c coll --sort "{name: 1}"
      2018-10-25T15:50:07.210+0300    connected to: localhost
      {"_id":0.0,"name":"Alex"}
      {"_id":3.0,"name":"Aristotle"}
      {"_id":1.0,"name":"Bart"}
      {"_id":2.0,"name":"Maria"}
      2018-10-25T15:50:07.210+0300    exported 4 records
      
      mongoexport -d test -c coll --sort "{name: -1}"
      2018-10-25T15:49:42.010+0300    connected to: localhost
      {"_id":2.0,"name":"Maria"}
      {"_id":1.0,"name":"Bart"}
      {"_id":3.0,"name":"Aristotle"}
      {"_id":0.0,"name":"Alex"}
      2018-10-25T15:49:42.011+0300    exported 4 records
      

      导出集合后,您可以在命令行中执行 diff 或使用 Beyond Compare 等图形用户界面 (GUI) 工具。

      仅供参考:如果您的文档可能具有相同的数据但具有不同的 _id 值: 导出时可以排除 _id 字段,如下所示:https://stackoverflow.com/a/49895549/728287

      【讨论】:

        【解决方案7】:

        Mongo 4.4 开始,聚合框架提供了一个新的$unionWith 阶段,执行两个集合的并集(来自两个集合的组合管道结果到一个结果集中)。

        更容易找到两个集合之间的差异:

        // > db.test.find()
        //    { "a" : 9, "b" : 2  }
        //    { "a" : 4, "b" : 12 }
        //    { "a" : 3, "b" : 5  }
        //    { "a" : 0, "b" : 7  }
        //    { "a" : 7, "b" : 12 }
        // > db.prod.find()
        //    { "a" : 3, "b" : 5  }
        //    { "a" : 4, "b" : 12 }
        //    { "a" : 3, "b" : 5  }
        //    { "a" : 0, "b" : 7  }
        db.test.aggregate(
          { $unset: "_id" },
          { $project: { from: "test", doc: "$$ROOT" } },
          { $unionWith: {
              coll: "prod",
              pipeline: [
                { $unset: "_id" },
                { $project: { from: "prod", doc: "$$ROOT" } }
              ]
          }},
          { $group: {
              _id: "$doc",
              test: { $sum: { $cond: [ { $eq: ["$from", "test"] }, 1, 0 ] } },
              prod: { $sum: { $cond: [ { $eq: ["$from", "prod"] }, 1, 0 ] } }
          }},
          { $match: { $expr: { $ne: ["$test", "$prod"] } } }
        )
        // { "_id" : { "a" : 7, "b" : 12 }, "test" : 1, "prod" : 0 }
        // { "_id" : { "a" : 9, "b" : 2  }, "test" : 1, "prod" : 0 }
        // { "_id" : { "a" : 3, "b" : 5  }, "test" : 1, "prod" : 2 }
        

        这个:

        • $unsets _id 以便后者能够在不考虑 _id 的情况下自行处理 $group 文档(因为它在其他集合中可能不同)。
        • $projects 字段 from 的值是文档来自的集合(testprod),以便在我们合并两个集合时跟踪文档的来源。李>
        • 还有$projects 字段doc,其值为文档本身(感谢$$ROOT 变量)。这是将用于$group 文档的字段。
        • $unionWith prod 集合,以便将两个集合中的文档合并到同一个聚合管道中。 pipeline 参数是一个可选的聚合管道,在将文档插入下游管道之前,应用于正在合并的集合 (prod) 中的文档。我们正在应用与 test 文档相同的 $unset/$project 阶段。
        • $groups testprod 文档基于我们为表示实际文档而创建的 doc 字段。我们将testprod 这两个字段累积为来自一个或另一个集合的分组文档的$sum(计数)(通过$cond if 表达式)。
        • $matches 通过仅保留测试和产品文档数量不同的项目来生成分组元素:两个集合之间的实际差异。

        【讨论】:

          猜你喜欢
          • 2017-04-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-31
          • 1970-01-01
          • 2011-10-17
          相关资源
          最近更新 更多