22

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

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

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

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

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

  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. 尝试实现无数据库分类。

请给我关于这件事的建议。我是任何 NoSQL 的新手(目前我没有设计过这样的数据库),所以对我来说有一个真正的设计问题。

而且我是堆栈的新手*,所以如果我在这篇文章中做错了什么,请随时纠正我:) 谢谢!

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

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

4

2 回答 2

8

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

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

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

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

于 2013-01-12T20:20:11.137 回答
5

首先,如果您不熟悉基本原理,则很难在 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
            }
         }
     }
    

这样你就可以运用你的索引想法并找到 where db.region.$.568=1

于 2013-01-12T02:07:30.593 回答