【问题标题】:Modeling Many-to-Many Relationships in Postgresql在 Postgresql 中建模多对多关系
【发布时间】:2021-06-12 12:15:44
【问题描述】:

我正在使用 Postgresql。

我需要一些帮助来设计我的数据库的最佳方式。

在它的核心,我的 web 应用程序有一个实体,我将其称为项目集合 - 想想“10 必读的太空旅行书籍”。 这里的项目是一本“太空旅行书”,而一个集合是 10 个此类项目的列表,在本例中是书籍。 所以,我有以下表格:

**Collections**
Id
Name
itemId
Author (need help on this field)

**Items**
Id
Name
Description
<Other Fields>

**Users**
Id
Name
Email
<Other fields>

问题 1: 用户可以登录并开始新的收藏。此用户是此集合的所有者。但是,他可以邀请/允许其他用户在此列表上进行协作,这意味着其他用户可以向其中添加项目。这意味着该集合现在有多个用户在处理它。对此进行建模的最佳方法是什么?如何为集合添加多个用户(可能具有不同的角色)。

我想的一种方法是让作者保持独立并设置一个具有多对多关系的合作者字段。这是个好主意吗?还有其他想法吗?

问题 2: 查看收藏的普通用户可以为收藏中的项目点赞,收藏中项目的顺序由点赞的数量决定。存储赞成票的最佳方式是什么?

【问题讨论】:

    标签: sql postgresql database-design


    【解决方案1】:

    由于您使用的是 Postgres,因此您希望 normalize your tables。归一化的意思,一句话,就是你的列由键、整个键表示,只有键表示。规范化可以是一个三步过程,但我只是要展示最终结果。

    通常,在数据库中,表名是单数的。用户、集合、项目。此外,使用表名命名您的 ID 字段也不会造成混淆。它使 join SQL 更易于阅读。

    让我们从 User 表开始。

    User
    ----
    User ID
    User Name
    User Email
    ...
    

    到目前为止,一切都很好。所有列都与用户有关。

    接下来,我们来看看Collection

    Collection
    ----------
    Collection ID
    Collection Name
    Owner ID
    

    到目前为止,一切都很好。所有者 ID 是集合所有者的用户 ID。

    接下来,我们来看看Item。

    Item
    ----
    Item ID
    Item Name
    Item Description
    ...
    

    到目前为止,一切都很好。所有的列都与一个项目有关。

    现在,让我们看看你在问题 1 中描述的 Collection 和 Item 之间的关系。一个 Collection 可以有一个或多个项目。一个项目可以在一个或多个集合中。

    当您具有多对多关系时,您将创建一个联结表。所以让我们创建一个 CollectionItem 联结表。

    CollectionItem
    --------------
    CollectionItem ID
    Collection ID
    Item ID
    CollectionItem timestamp
    CollectionItem contributor ID
    

    其中 CollectionItem ID 是主集群键。您在 (Collection ID, Item ID) 上也有一个唯一索引,因此您可以将集合拉到一起。您还可以在 (Item ID, Collection ID) 上有一个唯一索引,这样您就可以看到哪些项目在多个集合中。

    您还拥有一个关于(Collection ID、CollectionItem 贡献者 ID)的唯一索引。这使您可以查看哪个贡献者(用户)将项目贡献给集合。此用户 ID 可以是集合行中的所有者 ID,也可以是其他贡献者。

    看看问题 2,我们需要一个投票表。 Vote 表是另一个连接集合、项目和投票者(用户)的连接表。

    Vote
    ----
    Vote ID
    Collection ID
    Item ID
    Voter ID
    Vote timestamp
    

    其中 Vote ID 是主集群键,并且您在 (Collection ID, Item ID, Voter ID) 上有一个唯一索引。您可能还有另外两个唯一索引,具体取决于您是否要按投票者或项目对投票进行分组。

    编辑添加:

    您还需要某种权限表。

    Permission
    ----------
    Permission ID
    Owner ID
    Contributor ID
    

    其中 Permission ID 是主集群键,并且您在 (Owner ID, Contributor ID) 上有一个唯一索引。你也可以有一个你没有定义的权限类型,所以我不能把它添加到权限表中。权限类型也是唯一索引的一部分。

    我希望这个解释对你有所帮助。

    【讨论】:

    • 谢谢。从上面看不清楚的一件事是我们如何知道某人是否真的可以为收藏做出贡献。只有收藏所有者可以邀请用户为其收藏贡献内容。
    • @asanas:这是用户表和用户表之间的另一个联结表。您没有为我提供足够的信息来定义该联结表。
    • 好的,谢谢。那会是另一张桌子吗?你能帮忙定义一下吗?
    • 好的,我明白了。我认为权限表将授予集合权限。我可以有collection_id和contributor_id。
    【解决方案2】:
    1. 每个集合都有一个作者,因此在集合表中有一个作者列是完美的。
    2. 不过,每个集合可以有多个项目,这是一个 m:n 关系。
    3. 然后您希望允许其他用户将项目添加到集合中。一个用户可以被邀请到多个集合,一个集合可以有多个被邀请者。一个 m:n 关系。这也意味着我们应该将贡献用户与添加到集合中的项目一起存储。
    4. 然后你想存储赞成票。一个用户可以为许多收藏项投票,而一个收藏项可以被许多用户投票。再次 m:n。

    我们最终得到了这些表格:

    • 用户:ID、姓名、电子邮件、...
    • 项目:ID、名称、描述、...
    • 集合:id、name、author_user_id
    • Collection_Item:id、collection_id、item_id、user_id
    • 受邀者:collection_id、invitee_user_id
    • 点赞:collection_item_id、user_id

    使用此数据模型,您可以检查用户是否已被邀请加入收藏集,然后才允许他们为项目做广告。但是,如果您希望 DBMS 确保这一点,您必须将“受邀者”更改为“贡献者”并将作者自己添加到此表中。然后将 Upvote.user_id 更改为 Upvote.contributor_id 并将外键从“Collection_Item”添加到“Contributor”。

    【讨论】:

      猜你喜欢
      • 2020-06-03
      • 2017-01-02
      • 1970-01-01
      • 1970-01-01
      • 2019-08-21
      • 2013-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多