比较两个集合的 mongo 差异

Posted

技术标签:

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

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

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

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

【问题讨论】:

【参考方案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://***.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 通过仅保留测试和产品文档数量不同的项目来生成分组元素:两个集合之间的实际差异。

【讨论】:

以上是关于比较两个集合的 mongo 差异的主要内容,如果未能解决你的问题,请参考以下文章

在mono中使用c#驱动程序比较mongo集合的两个字段

Lodash / javascript:比较两个集合并返回差异[重复]

C# 实体/集合差异比较,比较两个实体或集合值是否一样,将实体2的值动态赋值给实体1(名称一样的属性进行赋值)

比较同一集合中的两个字段

mongo加入两个集合

mongo之 前后台创建索引 --noIndexBuildRetry