我期待设计一个数据库模式来比较两个产品。像这样的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.
}
]
我会考虑将功能设置为单独的集合,并为每个类别或产品提供功能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]}
这有几个好处:
无论如何,这是我的建议。如果在类别和产品集合中为features数据添加索引,那么执行查找,连接,过滤器等数据库操作将非常快。
编辑(回复你的评论):
对特征名称进行非规范化的决定与决定存储特征记录的位置是正交的。让我翻译一下:-)
规范化数据意味着您只保留任何数据的一个副本,然后在需要时引用该数据。这样,数据只有一个明确的来源,并且您不会遇到数据的不同副本最终被更改并且不再一致的问题。
在关系理论下,您希望尽可能地标准化数据,因为这是保持一致性的最简单方法。例如,如果您只有一个地方来记录客户地址,那么您将永远不会遇到有两个地址并且您不知道哪一个是正确的地址的情况。然而,出于性能原因,人们经常对数据进行去标准化,即避免昂贵和/或频繁的查询。对数据进行反规范化的决定必须权衡性能优势与手动维护数据一致性的成本(现在必须编写应用程序代码以确保数据的各个副本在任何一个数据更新时保持一致)。
这就是我的意思是去规范化与数据结构正交:你选择最合理的数据结构来准确地表示你的数据。然后,出于性能原因,有选择地对其进行去标准化。当然,如果不考虑性能影响,就不会选择最终的数据结构,但从概念上讲,它们是两个不同的目标。那有意义吗?
那么让我们来看看你的例子吧。目前,您将功能名称从类别功能列表复制到产品功能列表。这是非规范化。允许您在每次需要列出产品时避免查询类别集合的一种方法。您需要在性能优势与数据一致性问题之间取得平衡。因为现在,如果有人更改了产品或类别记录中的名称,则需要使用应用程序代码手动更新其他集合中的相应记录。如果您更改类别方面的名称,则可能需要更改数百条产品记录。
我假设你考虑过这些权衡,并相信去标准化的性能优势是值得的。如果是这种情况,那么没有什么可以阻止您从单独的要素集中去标准化。只需将要素集中的名称复制到类别或产品文档中即可。您仍然可以获得我列出的所有优势,并且性能不会比您当前的系统差。
OTOH,如果你还没有考虑过性能优势,并且只是遵循这个范例,因为“noSQL没有加入”,那么我的建议就是不要那么教条! :-)你可以很快地在MongoDB中进行连接,就像你可以很容易地在SQL表中对数据进行非规范化一样。这些并不是硬性规定。
FWIW,恕我直言,我认为避免简单查询的去规范化就是过早优化的情况。除非您的网站每秒服务> 10k产品页面以及> 1k插入或更新/秒导致大量锁定延迟,否则对功能集合的额外读取查询(特别是如果您已正确编制索引)将增加非常小的开销。即使在这些情况下,您也可以在需要开始非规范化之前对查询进行大量优化(例如,在显示多个产品的类别页面中,您可以执行一次批处理查询以检索单个查询中的所有功能记录)。
注意:有两种方法可以避免这两种方法,即使每个功能名称都是唯一的,然后将其用作密钥。也就是说,如果需要功能集合中的其他数据,请不要存储featureId,只存储功能名称,并根据该名称进行查询。但是,我强烈建议不要这样做。我个人教条的一件事是主键永远不应包含任何有用的信息。您可能认为它现在很聪明,但是从现在起一年后,您将诅咒您的决定(例如,当您决定将网站国际化时会发生什么,并且每个功能都有多个名称?如果您想要更广泛的过滤器怎么办?每个特征都有多个同义词,其中很多都重叠?)。所以我不推荐这条路线。就个人而言,我宁愿采取查询的最小额外开销。