【问题标题】:MongoDB (noSQL) when to split collectionsMongoDB(noSQL)何时拆分集合
【发布时间】:2015-07-16 12:19:53
【问题描述】:

所以我正在用 NodeJS 和 ExpressJS 编写一个应用程序。这是我第一次使用像 MongoDB 这样的 noSQL 数据库,我正试图弄清楚如何修复我的数据模型。

在开始我们的项目时,我们已经用关系数据库术语写下了所有内容,但自从我们最近从 Laravel 切换到 ExpressJS 的项目以来,我有点纠结于如何处理我所有不同的表格布局。

到目前为止,我发现最好非规范化您的方案,但它确实必须在某个地方结束,对吗?最后,您可以最终将整个数据存储在一个集合中。好吧,不是认真的,但你明白了。

1.那么是否有一个 rulestandard 来定义在哪里剪切以制作多个集合? 我有一个与用户(客户或商店用户)、商店、产品、购买、类别、子类别的关系数据库..

2。在 noSQL 数据库中定义关系是不是很糟糕? 就像每个产品都有一个类别一样,但我想通过 id 与类别相关联(父母在 MongoDB 中完成工作),但这是一件坏事吗?或者这是您选择性能还是结构的地方?

3. noSQL/MongoDB ment 是否可以用于关系很多的大型数据库(如果它们是在 MySQL 中制作的)?

提前致谢

【问题讨论】:

    标签: node.js mongodb


    【解决方案1】:

    如前所述,没有像 SQL 的第二范式这样的规则。

    但是,我将在此处列出与 MongoDB 优化相关的一些最佳实践和常见陷阱。

    过度使用嵌入

    BSON 限制

    与流行的看法相反,引用并没有错。假设您有一个图书馆,并且您想要跟踪租金。你可以从这样的模型开始

    {
      // We use ISBN for its uniqueness 
      _id: "9783453031456"
      title: "Schismatrix",
      author: "Bruce Sterling",
      rentals: [
        {
          name:"Markus Mahlberg,
          start:"2015-05-05T03:22:00Z",
          due:"2015-05-12T12:00:00Z"
        }
      ]
    }
    

    虽然此模型存在几个问题,但最重要的问题并不明显 - 由于 BSON 文档的大小限制为 16MB,因此出租数量有限

    文档迁移问题

    将租金存储在数组中的另一个问题是,这会导致相对频繁的文档迁移,这是一项相当昂贵的操作。 BSON 文档永远不会被分区和创建,并在它们增长时预先分配一些额外的空间。这个额外的空间称为填充。当超出填充时,文档将移动到数据文件中的另一个位置并分配新的填充空间。如此频繁地添加数据会导致频繁的文档迁移。 因此,最佳做法是防止频繁更新增加文档的大小并改用引用。

    因此,对于示例,我们将更改单个模型并创建第二个模型。一、本书的模型

    {
      _id: "9783453031456",
      title:"Schismatrix",
      author: "Bruce Sterling"
    }
    

    出租的第二个模型如下所示

    {
      _id: new ObjectId(),
      book: "9783453031456",
      rentee: "Markus Mahlberg",
      start: ISODate("2015-05-05T03:22:00Z"),
      due: ISODate("2015-05-05T12:00:00Z"),
      returned: ISODate("2015-05-05T11:59:59.999Z")
    }
    

    作者或承租人当然可以使用相同的方法。

    过度标准化的问题

    让我们回顾一下。开发人员将识别业务案例中涉及的实体,定义它们的属性和关系,编写相应的实体类,用头撞墙几个小时,以使三重内部-外部-高于和超越 JOIN 工作所需对于用例,所有人从此过上幸福的生活。那么为什么要普遍使用 NoSQL 而特别是 MongoDB 呢?因为没有人从此过上幸福的生活。这种方法扩展得非常可怕,几乎唯一的扩展方法是垂直的。

    但 NoSQL 的主要区别在于,您可以根据需要回答的问题对数据进行建模。

    话虽如此,让我们看一个典型的 n:m 关系,并以作者与书籍的关系为例。在 SQL 中,您将有 3 个表:两个用于您的实体(booksauthors),一个用于关系(谁是哪本书的作者? )。当然,您可以使用这些表并创建它们的等效集合。但是,由于 MongoDB 中没有 JOIN,因此您需要三个查询(一个用于第一个实体,一个用于其关系,一个用于相关实体)来查找实体的相关文档。这是没有意义的,因为 n:m 关系的三表方法是专门为克服 SQL 数据库强制执行的严格模式而发明的。 由于 MongoDB 有一个灵活的模式,第一个问题是在哪里存储关系,记住过度使用嵌入引起的问题。由于作者在未来几年可能会写很多书,但一本书的作者身份很少(如果有的话)改变,答案很简单:我们将作者作为对作者的参考存储在书籍数据中

    {
      _id: "9783453526723",
      title: "The Difference Engine",
      authors: ["idOfBruceSterling","idOfWilliamGibson"]
    }
    

    现在我们可以通过两个查询找到该书的作者:

    var book = db.books.findOne({title:"The Difference Engine"})
    var authors = db.authors.find({_id: {$in: book.authors})
    

    我希望以上内容可以帮助您决定何时真正“拆分”您的收藏并避开最常见的陷阱。

    结论

    关于你的问题,这是我的答案

    1. 如前所述:,但牢记技术限制应该会让您知道何时可行。
    2. 还不错——只要它适合您的用例。如果您有给定的类别及其_id,则很容易找到相关产品。加载产品时,您可以轻松获取产品所属的类别,甚至效率更高,因为默认情况下会为 _id 编制索引。
    3. 我还没有找到使用 MongoDB 无法完成的用例,尽管使用 MongoDB 可能会有些复杂。恕我直言,你应该做的是总结你的功能和非功能需求,并检查优点是否大于缺点。我的经验法则:如果您的需求列表中有“可扩展性”或“高可用性/自动故障转移”之一,那么 MongoDB 值得一看。

    【讨论】:

    • 阅读您的帖子后,一切都变得有意义了。非常感谢!
    • @JesseStruyvelt 很高兴我能帮上忙。请记住,尽管我的示例远未完成——它们只是关于如何在 MongoDB 中进行数据建模的粗略模型。例如,分片增加了一个全新级别的复杂性,应该从一开始就考虑到这一点。
    【解决方案2】:

    在选择“NoSQL”存储解决方案而不是“关系”解决方案时,要考虑的“第一”件事是,事情“不会以相同的方式工作”,因此在设计上会做出不同的响应。

    更具体地说,诸如 MongoDB 之类的解决方案“并不意味着”“模拟”许多 SQL 中存在的“关系连接”结构,因此是“关系”后端,而且它们还旨在查看数据“连接” " 以一种非常不同的方式。

    您的“问题”如下:

    1. 确实没有固定的“规则”,并且理解非规范化的“规则”不适用于 NoSQL 解决方案存在的基本原因。那就是提供一些“不同”的东西,可能对你的情况很有效。

    2. 不好吗?好吗?两者都是主观的。考虑这里的第“1”点,基本考虑是“非关系”或“NoSQL”数据库被设计为与关系系统“不同”地做事。因此,以关系方式“模拟连接”通常会受到“惩罚”。特别是对于 MongoDB,这意味着“附加请求”。但这并不意味着您“不能”或“不应该”这样做。而是所有关于您的使用模式如何适用于您的应用程序。

    3. 重新总结上述基本观点,NoSQL 通常旨在解决不适合传统 SQL 和/或“关系”设计模式的问题,因此用其他东西代替它们。这里的“最终目标”是让您“重新考虑数据访问模式”并改进您的应用程序以使用更适合您在应用程序使用中访问它的方式的存储模型。

    简而言之,没有严格的规则,这也是远离“nth-normal-form”规则的一部分。 NoSQL 解决方案(例如 MongoDB)允许“嵌套结构”存储,而典型的 SQL/关系解决方案无法以有效的形式提供。

    另一方面是考虑到诸如“连接”之类的操作不能很好地“扩展”于“大数据”形式,因此存在通过提供“嵌入式数据结构”等概念来“连接”的不同方式,就像 MongoDB 那样。

    您最好阅读一些关于有多少 NoSQL 解决方案存储和访问数据的主题的指南。这最终是您需要决定的,以确定哪个最适合您和您的应用程序。

    归根结底,应该是意识到 SQL/关系模型何时满足您的需求,然后选择其他东西。

    【讨论】:

    • 感谢您快速详细的回答。所以简而言之,这只是存储和查询数据的一种完全不同的方法吗?不知何故,我仍然不完全理解关系/嵌入文档的东西和集合。你会把所有有关系的东西都嵌入到一个存储在集合中的文档中吗?并制作新的集合,该集合中的数据与其他任何东西都不相关?
    • 另外,假设我想要一个产品附加一个类别。我可以将它嵌入到 JSON 中,但如果我想重命名类别,我必须更改每个产品,因为它与父名称没有任何关系/引用。还是我在这里遗漏了什么?
    • @JesseStruyvelt 这是一种非常不同的方法。我建议至少阅读核心手册中的Data Modelling,以获取有关方法的一些一般指导。 “一对多”的概念当然取决于典型访问中涉及“多少数据”,最重要的是这是否违反了 MongoDB 提供的 BSON 文档的 64MB 限制。
    • 谢谢。现在还有一个问题。如果我将数据保存在我的用户(嵌入)等中,那么尽可能多地存储在单个文档中。你应该为你的收藏选择什么名字?所以最终或大部分时间你只有一个包含一个集合的数据库。现在感觉很奇怪……习惯了。
    • @JesseStruyvelt 你所问的内容相当迟钝,没有更详细的解释,如果你想了解一个要点的细节,这可能更适合在这个网站上提出单独的问题而不是一个单一的问题,以及当然,您可以通过这种方式比具体示例更清楚地说明这一点。在“广义”的意义上,一般的“约定”是使用“人”之类的东西来表示包含“人”的“复数”集合,但嵌入元素可以命名为“子项”的数组。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    • 2016-04-14
    • 1970-01-01
    相关资源
    最近更新 更多