如何找到与断开的“外键”关系等价物?

How to Find the Equivalent of Broken "Foreign Key" Relationships?

提问人:John Saunders 提问时间:5/23/2015 最后编辑:CommunityJohn Saunders 更新时间:5/23/2015 访问量:586

问:

我有两个集合,如果这是一个关系数据库,它们就属于我们所说的“一对一关系”。我不知道为什么一个没有嵌套在另一个文档中,但事实是,对于集合“A”中的每个文档,集合“B”中都应该有一个文档,反之亦然。

当然,在没有外键约束的情况下,在存在错误的情况下,有时“A”中的文档在“B”中没有相关文档(反之亦然)。

我是MongoDB的新手,我在创建查询或脚本时遇到了问题,该查询或脚本将找到“A”中的所有文档,而这些文档在“B”中没有相关文档(反之亦然)。我想我可以使用某种循环,但我还不知道它是如何工作的——我才刚刚开始在 RoboMongo 命令行上使用简单的查询。

谁能让我开始为此编写脚本?我看过“验证MongoDB中的引用(外键)完整性”,但这对我没有帮助。一个错误导致“引用完整性”崩溃,我需要脚本来帮助我跟踪错误。我也无法重新设计数据库以使用嵌入(尽管我希望我会问为什么一个文档没有嵌套在另一个文档中)。

我还看到了“如何使用 MongoDB 在集合中查找不在另一个集合中的项目”,但它没有答案。

不良技术的伪代码

var misMatches = [];
var collectionB = db.getCollection('B');
var allOfA = db.getCollection('A').find();
while (allOfA.hasNext()) {
    var nextA = allOfA.next();
    if (!collectionB.find(nextA._id)) {
        misMatches.push(nextA._id);
    }
}
mongodb mongodb查询

评论

1赞 mnemosyn 5/23/2015
“糟糕的技术”对我来说听起来很正确。这是怎么回事?循环中的查询可能应该有一个索引,否则简单地从数据库中获取所有数据(如果可能的话)可能是有意义的,或者使用具有较大基数的数据作为“根循环”。
0赞 John Saunders 5/23/2015
首先,我来自SQL Server的背景,我对这可能是我能做的最好的事情的想法感到非常震惊。我本来希望大部分工作都在数据库中完成。我认识到,如果数据库设计将 B 嵌套在 A 中,这永远不会发生。不过,假设我在两个字段上都有索引,我希望让MongoDB比较两个索引是否不匹配,而不是让我做所有的工作。_id
0赞 mnemosyn 5/23/2015
嗯,我明白了。恐怕这是不可能的。MongoDB中没有ACID'C',即一致性/不变性检查。
0赞 John Saunders 5/23/2015
我知道没有“C”。我正在尝试在事后检查不一致之处。事实上,可能是我的程序导致了不一致,我需要看看模式。我知道一个不一致的案例;我有一个,但如果只有一个坏文档,我就会寻找一个不同的错误,如果所有文档都是坏的,我会寻找一个不同的错误,如果它是多个文档但少于所有文档,则要寻找最糟糕的错误。在这种情况下,我需要查看不良文档以了解它们有什么共同点。
2赞 5/23/2015
collection.findOne() != null告诉您已找到结果或反之不匹配。像返回游标这样的方法,因此检查是不合逻辑的。.find()

答:

3赞 Sylvain Leroux 5/23/2015 #1

我不知道这是否能很好地扩展,但是......

...给定此示例日期集:

> db.a.insert([{a:1},{a:2},{a:10}       ])
> db.b.insert([      {b:2},{b:10},{b:20}])
//             ^^^^^              ^^^^^^
//                inconsistent 1-to-1 relationship

你可以使用 map-reduce 来收集 key 集,并将其与 from 中的 key 集合并:ab

mapA=function() {
  emit(this.a, {col: ["a"]})
}

mapB=function() {
  emit(this.b, {col: ["b"]})
}

reduce=function(key, values) {
  // merge both `col` arrays; sort the result
  return {col: values.reduce(
                 function(a,b) { return a.col.concat(b.col) }
                            ).sort()}
}

生产:

> db.a.mapReduce(mapA, reduce, {out:{replace:"result"}})
> db.b.mapReduce(mapB, reduce, {out:{reduce:"result"}})
> db.result.find()
{ "_id" : 1, "value" : { "col" : [ "a" ] } }
{ "_id" : 2, "value" : { "col" : [ "a", "b" ] } }
{ "_id" : 10, "value" : { "col" : [ "a", "b" ] } }
{ "_id" : 20, "value" : { "col" : [ "b" ] } }

然后很容易找到所有在集合中找不到的 id,并且 .此外,您应该能够在一个或另一个集合中发现重复的键:ab

> db.result.find({"value.col": { $ne: [ "a", "b" ]}})
{ "_id" : 1, "value" : { "col" : [ "a" ] } }
{ "_id" : 20, "value" : { "col" : [ "b" ] }