与NoSQL数据库的多对多关系

时间:2013-01-12 01:51:33

标签: database-design nosql many-to-many taxonomy document-oriented-db

我想为带有NoSQL数据库的node.js应用程序实现分类结构(地理术语)。我有一个与MySQL类似的分类结构,但现在是时候向前推进并学习新东西,所以我决定尝试不同的方法并使用NoSQL(面向文档)来测试我的测试应用程序。分类结构很简单 - 有五个不同的级别:国家(英国)→地区(英格兰)→县(默西塞德郡)→城市/城镇/村庄(利物浦)→城市的一部分(托克斯泰斯)。

显而易见的选择是使用树木结构,但魔鬼在细节 - 历史上一些城市和城镇属于其他县。这个想法是用那些术语来标记出生在某些城市或城镇的人,然后用地理标记过滤它们,所以我必须尊重利物浦或曼彻斯特(以及其他人)在某些人出生时属于兰开夏郡的事实。 。否则,任何用户使用我的地理过滤器获得的结果都将是错误的。

示例:John Doe于1957年出生于布莱克本(兰开夏郡)。保罗·布朗1960年出生于利物浦(兰开夏郡,现为默西塞德郡)。 Georgia Doe(nee Jones)5年后出生在威勒尔(柴郡,现在的默西塞德郡)。他们的儿子林戈于1982年出生于利物浦(当时是默西塞德郡)。

约翰是兰开斯特出生的,保罗是兰开斯特和梅西郡,佐治亚州同时来自柴郡和默西塞德郡,林戈来自默西塞德郡。所以当我按县搜索时,应该对它们进行相应的分类。但是,随着国家现代结构的简单一对多结构,他们永远不会被过滤掉。

如何使用NoSQL(首先是面向文档的)解决方案来实现集合的复杂性?我用Google搜索并对堆栈进行了一些研究*但仍然不知道下一步该做什么。在我看来,有几种可能的解决方法:

  1. 使用类似SQL的数据结构:

    {
        {'name': 'United Kingdom', 'unique_id': 1},
        {'name': 'England', 'unique_id': 2, 'parents': [1]},
        {'name': 'Merseyside', 'unique_id': 3, 'parents': [2]},
        {'name': 'Lancashire', 'unique_id': 4, 'parents': [2]},
        {'name': 'Liverpool', 'unique_id': 5, 'parents': [3, 4]},
    }
    
  2. 使用树结构和一些引用:

    {    
        {'name': 'United Kingdom', 'unique_id': 1
            {'name': 'England', 'unique_id': 2]
                {'name': 'Merseyside', 'unique_id': 3]
                    {'name': 'Liverpool', 'unique_id': 5, 'alternate_parents': [4]},
                },
                {'name': 'Lancashire', 'unique_id': 4},
            },
        },
    }
    
  3. 使用没有引用的树结构(一对多)并手动将“alternate parent”标记添加到文档中:

    {    
        {'name': 'United Kingdom', 'unique_id': 1
            {'name': 'England', 'unique_id': 2]
                {'name': 'Merseyside', 'unique_id': 3]
                    {'name': 'Liverpool', 'unique_id': 5},
                },
                {'name': 'Lancashire', 'unique_id': 4},
            },
        },
    }
    
  4. 坚持使用SQL。

  5. 尝试实施无数据库分类。
  6. 请就此事给我建议。我是任何NoSQL的新手(目前我没有设计过这样的数据库),所以对我来说有一个真正的设计问题。

    我是新手堆叠*所以如果我对这篇文章做错了,请随时纠正我:)谢谢!

    修改 我选择@Jonathan答案作为解决方案。我认为它更适合我的需求(我的数据库中会存储其他文档并使用这些术语标记它们),尤其是@Valentyn建议的mapReduce功能。

    但如果你的应用程序不需要文档集合,那么@Philipp建议的图形数据库(基于关系而不是文档)可能是最好的解决方案。

2 个答案:

答案 0 :(得分:7)

由于您所做的评论,我认为当您说“NoSQL”时,您的意思是“MongoDB”。还有很多其他数据库技术通常被称为NoSQL,这些技术完全不同,但这个技术似乎就是你的意思。

  1. 不是一个好主意,因为要获得整个分类链,您需要进行多个数据库查询,这通常应该避免。

  2. 和3.单个文档是一棵巨大的树也不是一个好主意,因为MongoDB每个文档的限制为16MB。当您创建巨大的单片文档时,您可能会达到这个限制。

  3. 我认为MongoDB可能不是您用例的最佳解决方案。您考虑使用graph database吗? MongoDB针对独立的文档进行了优化,这些文档独立存在。但是图形数据库的重点是数据集,在这些数据集中,你有很多实体,这些实体是由它们与其他实体的关系定义的。这看起来很像你的用例。

答案 1 :(得分:4)

首先,如果您不熟悉基本原则,那么在NoSQL和SQL数据库之间进行选择是很困难的。如果这是您存储的唯一数据,请使用关系(SQL)。如果有更多的数据(我假设)并且它需要更多的交织模式,那么坚持使用NoSQL。

我会采用关系路线来防止它过于复杂......开始几个集合;一个国家,地区等。不要气馁在NoSQL数据库中执行关系(SQL)类型模式;大多数时候,他们是最好的解决方案。

然后,在每个子组中,都有一个命名父组的字段。

例如:

{
    {'name': 'United Kingdom'},
    {'name': 'United States'}
}

{
    {'name': 'England', 'parent': 'United Kingdom'},
    {'name': 'California', 'parent': 'United States'}
}

这样,您的数据集不会嵌套,导致返回的数据无法管理。然后,您可以轻松地抓住国家和相应的地区......等。

祝你好运!

编辑:回答OP的问题:

(首先,我推荐MongoDB - 这是一个很好的解决方案。)

  1. 因为当你开始使用MongoDB时,你会发现它将数据并排存储在硬盘上。如果您编辑这样一个巨大的记录,它很可能被推到磁盘的后面,使您的硬盘类似于瑞士奶酪。一旦达到这一点,你将不得不进行修复以再次压缩它。此外,通过这种方式,数据在应用程序中更容易分离,这样,如果您需要对数据执行某些操作,则不必将其应用于整个对象。我假设您将拥有一个大型数据集,因为世界上有许多不同的位置。

  2. 不要太担心这种事情。如果您计划大量更改名称,则可以将ID用于父级,并将子级与ID匹配。我这样做是因为我假设您不需要更改位置数据库。

  3. 我会使用嵌套文档来存储多个父项,而不是数组。这样,可以更容易地查询和索引。我会使用以下方法:

    {
        {
            'name': 'England,
            'parent': {
                1: 1,
                568: 1
            }
         }
     }
    
  4. 通过这种方式,您可以使用索引的概念并找到db.region.$.568 = 1

    的位置