如何找到损坏的“外键”关系的等价物?

Posted

技术标签:

【中文标题】如何找到损坏的“外键”关系的等价物?【英文标题】:How to Find the Equivalent of Broken "Foreign Key" Relationships? 【发布时间】:2015-05-23 03:04:10 【问题描述】:

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

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

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

任何人都可以让我开始使用脚本吗?我见过“Verifying reference (foreign key) integrity in MongoDB”,但这对我没有帮助。一个错误导致“参照完整性”崩溃,我需要脚本来帮助我追踪错误。我也无法重新设计数据库以使用嵌入(尽管我希望我会问为什么一个文档没有嵌套在另一个文档中)。

我也看过“How to find items in a collections which are not in another collection with 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);
    

【问题讨论】:

“糟糕的技术”听起来对我来说是正确的。它有什么问题?循环中的查询可能应该有一个索引,否则简单地从数据库中获取所有数据(如果可能)可能是有意义的,或者使用具有较大基数的数据作为“根循环”。 首先,我有 SQL Server 背景,我对这可能是我能做的最好的想法感到非常震惊。我希望大部分工作都在数据库中完成。我认识到,如果数据库设计将 B 嵌套在 A 中,这将永远不会发生。尽管如此,假设我在两个 _id 字段上都有索引,我希望 MongoDB 比较这两个索引是否不匹配,而不是让我完成所有工作。 嗯,我明白了。恐怕这是不可能的。没有 ACID 'C',即 MongoDB 中的一致性/不变性检查。 我知道没有“C”。我试图在事后检查不一致之处。实际上,可能是我的程序导致了不一致,我需要查看模式。我知道一个不一致的情况;我有一个,但要查找是否只有一个坏文档,如果 all 文档都不好,则要查找不同的错误,如果它是多于一个文档但少于所有文档,则要查找最糟糕的错误文件。在那种的情况下,我需要查看不良文档以了解它们的共同点。 collection.findOne() != null 告诉您找到了一个结果,或者相反没有匹配。 .find() 之类的方法返回一个游标,因此检查不合逻辑。 【参考方案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 收集 a 中的键集并将其与 b 中的键集合并:

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" ]  

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

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

【讨论】:

以上是关于如何找到损坏的“外键”关系的等价物?的主要内容,如果未能解决你的问题,请参考以下文章

Restkit:外键关系的存根

powerdesigner如何设置主外键关系?

如何找到所有mysql表之间的所有关系?

给已有数据的oracle表建立外键关系

如何在“菱形”关系系统中保持外键关系一致

如何与SQLite建立关系(外键)