比较两个集合的 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.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
然后我们可以创建一个 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.__v
和 doc2.__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
这个:
$unset
s _id
以便后者能够在不考虑 _id
的情况下自行处理 $group
文档(因为它在其他集合中可能不同)。
$project
s 字段 from
的值是文档来自的集合(test
或 prod
),以便在我们合并两个集合时跟踪文档的来源。李>
还有$project
s 字段doc
,其值为文档本身(感谢$$ROOT
变量)。这是将用于$group
文档的字段。
$unionWith
prod
集合,以便将两个集合中的文档合并到同一个聚合管道中。 pipeline
参数是一个可选的聚合管道,在将文档插入下游管道之前,应用于正在合并的集合 (prod
) 中的文档。我们正在应用与 test
文档相同的 $unset
/$project
阶段。
$group
s test
和 prod
文档基于我们为表示实际文档而创建的 doc
字段。我们将test
和prod
这两个字段累积为来自一个或另一个集合的分组文档的$sum
(计数)(通过$cond
if 表达式)。
$match
es 通过仅保留测试和产品文档数量不同的项目来生成分组元素:两个集合之间的实际差异。
【讨论】:
以上是关于比较两个集合的 mongo 差异的主要内容,如果未能解决你的问题,请参考以下文章
Lodash / javascript:比较两个集合并返回差异[重复]