MongoDB - 子和父结构

 手机用户2502924641 发布于 2022-12-11 22:36

刚刚使用MongoDB深入研究NoSQL的世界,我仍然在努力理解最佳的体系结构方法,而不需要对数据进行标准化,然后加入数据.目前我正在设计的项目是一个简单的文章集,类似于维基.一篇文章将有一个标题和文本,以及(可能)一篇父文章和一篇或多篇儿童文章.

我对数据库设计有很多不同的想法,并希望选择最符合MongoDB强度的那个.

想法一

由于数据库上最常见的查询类型总是简单地检索文章,因此我将嵌入页面所需的所有相关数据以显示所有内容.当然,实际的文章,以及带有url的父子文档(将与其他文档的_id匹配)以及标题,我们将在屏幕上为标记内部打印出来的文本.除了它是一个数组以便所有孩子都在那里之外,孩子们都存在一个身份结构.

{
        "_id" : "test-article-2",
        "title" : "Test Article 2",
        "text" : "Blah 2",
        "parent" : {
                "title" : "Test Article",
                "url" : "test-article"
        },
        "children" : [
                {
                        "title" : "Test Article 3",
                        "url" : "test-article-3"
                }
        ]
}

这种类型的设计似乎具有速度的优势(在我看来),但我想听听这个设计的其他东西.

想法二

更多的是我习惯于来自关系数据库世界.不是将子对象嵌入到设计中,而是简单地放入它们的唯一标识符.因此,parent现在只包含一个文本字符串,该字符串将与其他文档的_id匹配,并且子类同样具有链接到_id的字符串数组.

然而,为了获得查看文章的所有信息,我们现在需要进行一些查询(至少我认为我们需要...)一个获取主要文章,然后另一个获取父级标题放入标签,然后另一个获得所有儿童文章,同样获得他们的标题.

这似乎只是为了显示一篇文章而进行更多的查询,但是如果删除或更新某些文章,它可能会使数据库的更新变得更容易.(再次不确定那一点).

{
        "_id" : "test-article-2",
        "title" : "Test Article 2",
        "text" : "Blah 2",
        "parent" : "test-article",
        "children" : [ "test-article-3", "test-article-4"]
}

很高兴听到那些有更多MongoDB设计经验的人的意见.

1 个回答
  • 您需要考虑需要执行的查询类型以及每种类型需要的频率.当我在做类似的事情时,我提出了六个可能的行动:

    与父母做点什么

    和孩子们做点什么

    与祖先做些事(父母的父母,父母的父母等)

    与后代做一些事情(孩子的孩子,孩子的孩子等)

    更改关系(在层次结构中添加/移动/删除节点)

    更改当前节点中的主数据(例如,更改"标题"字段中的值)

    您需要估计每个应用程序对您的应用程序的重要程度.

    如果您的大部分工作涉及使用某些特定文章(包括其直接父母和孩子)的存储数据,那么第一个想法是最有用的.实际上,在MongoDB中,将所需的所有信息放在同一文档中而不是在外部引用它是很常见的,这样您只需要检索一件事并只使用该数据.列表中的最后四个动作虽然更棘手.

    特别是,在这种情况下,您将需要遍历树以检索祖先和后代,移动中间文档并遵循路径,即使您可能只关心路径中的最后一个文档.对于长层次结构,这可能很慢.改变关系可能需要在多个文档中移动大量信息,因为每个文档中存在所有数据.但即使更改像"标题"这样的单个字段也会令人讨厌,因为您必须考虑这个字段存在于多个不同文档中的事实,无论是作为主字段还是在父字段或子字段下.

    基本上,您的第一个想法最适用于更多静态应用程序,在这些应用程序中,您最初创建数据后不会对数据进行大量更改,而是需要定期读取数据.

    MongoDB文档有五种推荐的方法来处理树状(分层)结构.所有这些都有不同的优点和缺点,尽管它们只需要在一篇文档中更新主要数据就可以轻松更新.

    父引用:每个节点都包含对其父节点的引用.

    优点:

    快速父查找(通过"_id"查找=您的文档标题,返回"父"字段)

    快速查找子项(按"父"查找=您的文档标题,将返回所有子文档)

    更新关系只需更改"父"字段即可

    更改基础数据只需要更改一个文档

    缺点:

    由祖先和后代搜索很慢,需要遍历

    子引用:每个节点都包含一个引用其子代的数组

    优点:

    快速检索孩子(返回子阵列)

    快速关系更新(只需更新子项的数组)

    缺点:

    查找父级需要在所有文档的所有子数组中查找_id,直到找到它为止(因为父级将包含当前节点作为子级)

    祖先和后代搜索需要遍历树

    祖先数组:每个节点都包含对其祖先及其父级数组的引用

    优点:

    快速检索祖先(无需遍历以查找特定的祖先)

    按照"父参考"方法轻松查找父母和子女

    要找到后代,只需查看祖先,因为所有后代必须包含相同的祖先

    缺点:

    当关系发生变化时,需要担心保持祖先数组以及父字段更新,通常跨多个文档.

    物化路径:每个节点都包含一个自身路径 - 需要正则表达式

    优点:

    使用正则表达式很容易找到孩子和后代

    可以使用路径来检索父级和祖级

    灵活性,例如通过部分路径查找节点

    缺点:

    关系更改很困难,因为它们可能需要更改多个文档中的路径

    嵌套集:每个节点都包含一个"左"和"右"字段,以帮助查找子树

    优点:

    通过在"左"和"右"之间搜索,以最佳方式轻松检索后代

    像"父参考"方法一样,很容易找到父母和孩子

    缺点:

    需要遍历结构才能找到祖先

    关系更改在这里执行的结果比任何其他选项都要差,因为树中的每个文档都可能需要更改,以确保一旦层次结构发生变化,"左"和"右"仍然有意义

    MongoDB文档中更详细地讨论了这五种方法.

    您的第二个想法结合了上面讨论的"父参考"和"儿童参考"方法.这种方法可以很容易地找到子项和父项,并且可以轻松更新文章的关系和主要数据(尽管您需要更新父项和子项),但仍需要遍历它寻找祖先和后代.

    如果您有兴趣寻找祖先和后代(并且关心这一点而不是能够轻松更新关系),您可以考虑在您的第二个想法中添加祖先数组,以便查询祖先和后代.当然,如果你这样做,更新关系会变得非常痛苦.

    结论:

    最终,这一切都取决于最需要的行动.由于您正在使用文章,其基础数据(如标题)可能经常更改,您可能想要避免第一个想法,因为您不仅需要更新该文章的主文档,还需要更新所有子文档以及家长.

    您的第二个想法可以轻松检索直接的父母和孩子.更新关系也不是太困难(它肯定比其他一些可用的选项更好).

    如果您真的希望以牺牲更新关系为代价来轻松找到祖先和后代,请选择包含一系列祖先引用.

    通常,尽量减少所需的遍历次数,因为它们需要运行某种迭代或递归来获取所需的数据.如果您重视更新关系的能力,您还应该选择一个更改树中较少节点的选项(父引用,子引用,您的第二个想法可以执行此操作).

    2022-12-11 22:48 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有