比较两个集合上的mongo diff

Kar*_*ain 16 mongodb

我有两个mongo集合,一个是生产环境,另一个是测试环境.我如何比较其中两个之间的差异?我尝试将它们转储到bson然后转换为json.但我不能对它们执行简单的差异,因为排序可能会有所不同,而且json文件太大而无法排序.

Kev*_*ith 9

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

假设我们有2个集合db.col1并且db.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 }
Run Code Online (Sandbox Code Playgroud)

然后我们可以创建一个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;
}
Run Code Online (Sandbox Code Playgroud)

然后打电话如下:

> compareCollection(db.col1, db.col2)
true
Run Code Online (Sandbox Code Playgroud)

如果我们有第3个收藏 db.col3

> db.col3.find()
{ "_id" : 1, "item" : 1 }
Run Code Online (Sandbox Code Playgroud)

并比较这一个

> compareCollection(db.col1, db.col3)
false
Run Code Online (Sandbox Code Playgroud)

我们会得到预期的结果.

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

> db.col4.find()
{ "_id" : 1, "item" : 10 }
{ "_id" : 2, "item" : 2 }
{ "_id" : 3, "item" : 3 }
{ "_id" : 4, "item" : 4 }
Run Code Online (Sandbox Code Playgroud)

这也将回归 false

> compareCollection(db.col1, db.col4)
false
Run Code Online (Sandbox Code Playgroud)

  • 如果您有 500 万条记录...比较它们的唯一方法是检查所有 500 万条记录,我想如果您的文档中还有其他使它们独一无二的内容,您可以与之进行比较并将其作为索引,但是如果您需要检查它们是否匹配,您需要检查它们是否匹配 (3认同)
  • 如果我有 500 万条记录怎么办?这不会导致一些性能问题吗?难道就没有更直接的方法吗? (2认同)

Car*_*uez 8

使用凯文史密斯响应,我有一个新版本,仅用于比较和返回那些collectionB没有与collectionA. collectionC当您有很多记录时,将结果保存在 a 中。

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


Xav*_*hot 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 }
Run Code Online (Sandbox Code Playgroud)

这个:

  • $unsets_id以便后者能够在$group不考虑 the 的情况下自行记录_id(因为它在其他集合中可能不同)。
  • $projects 字段,from其值为文档来自的集合(testprod),以便在合并两个集合时跟踪文档的来源。
  • $projectsdoc其值为文档本身的字段(感谢$$ROOT变量)。这是将用于一起$group记录的字段。
  • $unionWithprod为了收集来自两个集合的文档合并到同一聚合管道。该pipeline参数是一个可选的聚合管道,prod在文档插入下游管道之前应用于正在合并的集合中的文档( )。我们正在应用我们在文档上应用的相同$unset/$project阶段test
  • $groupstestprod基于doc我们创建的用于表示实际文档的字段的文档。并且我们累积两个字段testprod作为$sum源自一个或另一个集合(通过$condif 表达式)的分组文档的(计数)。
  • $match通过只保留不具有相同数量的测试和生产文档的项目来生成分组元素:两个集合之间的实际差异。


tsv*_*iko 6

dbHash做的伎俩:

use db_name
db.runCommand('dbHash')
Run Code Online (Sandbox Code Playgroud)

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

  • _id将始终导致哈希错误 (5认同)