我正在寻找一种数据库模式来比较两种产品。像这样的https://www.capterra.com/agile-project-management-tools-software/compare/160498-147657/Clubhouse-vs-monday-com
这是我对数据库架构设计的想法(只能比较同一类别的产品,请注意数据库是mongodb):
但是,这使产品表与类别表紧密结合在一起。以前有人解决过这个问题吗?任何指针将不胜感激。这是架构的概述:
categories collection:
name: 'String'
features: [
{
name: 'string'
parent_id: 'ObjectID' // if this is a sub feature it will reference in this // embedded document itself
}
]
products:
name: 'String'
features: [ // Embedded document with feature values
{
name: 'String',
value: Boolean,
category_feature_id: 'ObjectID' // feature_id into the categories.features // table, majorly used to comparison only.
}
]
答案 0 :(得分:1)
我会考虑将功能单独收集,并为每个类别或产品提供功能ID列表。例如:
Features collection:
{id: XXX, name: A}, {id: YYY, name: B}
Categories collection:
{ features: [featureId: XXX, value: C]}
Products collection:
{ features: [featureId: YYY, value: D]}
这有几个优点:
无论如何,这是我的建议。而且,如果您在类别和产品集合中的功能Array中添加索引,那么执行数据库操作(例如查找,联接,过滤器等)将非常快。
编辑(以回复您的评论):
对特征名称进行非规范化的决定与对特征记录存储位置的决定正交。让我翻译一下:-)
标准化数据意味着您仅保留任何数据的一个副本,然后在需要时引用该数据。这样,就永远只有一个确定的数据源,而且您不会遇到数据的不同副本最终被更改且不再一致的问题。
根据关系理论,您希望尽可能规范化数据,因为这是保持一致性的最简单方法。例如,如果您只有一个地方来记录客户地址,那么您将永远不会陷入有两个地址并且不知道哪一个是正确地址的情况。但是,人们经常出于性能原因对数据进行非规范化,即避免昂贵和/或频繁的查询。对数据进行非规范化的决定必须权衡性能优势与手动维护数据一致性的成本之间的差异(您现在必须编写应用程序代码,以确保在更新其中任何一个数据时,各个数据副本保持一致)。
这就是我所说的去标准化与数据结构正交:您选择最有意义的数据结构来准确表示数据。然后,出于性能原因,有选择地对它进行规范化。当然,您不会在不考虑性能影响的情况下选择最终的数据结构,但是从概念上讲,它们是两个不同的目标。这有道理吗?
因此,让我们看一下您的示例。当前,您将功能名称从类别功能列表复制到产品功能列表。这是非规范化。这样一来,您就不必在每次需要列出产品时都查询类别集合。您需要在性能优势与数据一致性问题之间取得平衡。因为现在,如果有人更改了产品或类别记录中的名称,则需要使用应用程序代码来手动更新另一个集合中的相应记录。而且,如果您在类别侧更改名称,则可能需要更改数百个产品记录。
我假设您考虑了这些折衷,并认为去标准化的性能优势是值得的。如果是这种情况,那么也没有什么可以阻止您从单独的功能集中进行非规范化的。只需将功能集中的名称复制到类别或产品文档中即可。您仍然可以获得我列出的所有优点,并且性能不会比您当前的系统差。
OTOH,如果您还没有考虑过性能优势,而是因为“ noSQL不会加入”而只是遵循这种范例,那么我的建议就不要那么教条! :-)您可以非常快速地在MongoDB中进行联接,就像您可以非常轻松地对SQL表中的数据进行非规范化一样。这些不是一成不变的规则。
FWIW,恕我直言,我认为为了避免简单查询而进行的非规范化是过早优化的一种情况。除非您的网站每秒提供超过1万个产品页面,以及每秒超过1k次插入或更新,从而导致大量的锁定延迟,否则对功能集合进行额外的读取查询(尤其是如果您已正确建立索引)将增加非常小的开销。即使在这种情况下,您也可以在开始非规范化之前对查询进行很多优化(例如,在显示多个产品的类别页面中,您可以执行一个批处理查询以在单个查询中检索所有功能记录)。>
注意:有一种避免两种方法的方法,即使每个功能名称唯一,然后使用 that 作为键。也就是说,如果您需要来自功能部件集合的其他数据,则不存储功能部件编号,仅存储功能部件名称,并根据此名称进行查询。但是,我强烈建议不要这样做。我个人信奉的一件事是,主键永远不应包含任何有用的信息。您可能会认为它现在很聪明,但是从现在开始一年后,您将在诅咒您的决定(例如,当您决定对网站进行国际化并且每个功能都有多个名称时会发生什么情况?如果要使用更广泛的过滤器,该怎么办?每个功能都有多个同义词,其中许多重叠?)。所以我不推荐这条路线。就个人而言,我希望将查询的额外开销降到最低。