在 Postgresql 中建模 Many-to-Many 关系

Modeling Many-to-Many Relationships in Postgresql

我正在使用 Postgresql。

我需要一些帮助来设计我的数据库。

我的网络应用程序的核心是一个实体,我将其称为 collection 项 - 想想“Space 旅行必读的 10 本书”。 这里的项目是一本“关于 space”旅行的书,collection 是一个包含 10 个这样的项目的列表,在本例中是书。 所以,我有下表:

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

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

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

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

我考虑的一种方法是将作者分开并设置一个具有多对多关系的合作者字段。这是个好主意吗?还有其他想法吗?

问题二: 查看 collection 的普通用户可以对 collection 中的项目进行投票,并且 collection 中项目的顺序由点赞数决定。存储点赞的最佳方式是什么?

  1. 每个 collection 都有一个作者,所以在 collection table 中有一个作者栏是完美的。
  2. 每个 collection 可以有多个项目,但是,这是一个 m:n 关系。
  3. 然后您希望允许其他用户向 collection 添加项目。一个用户可以被邀请到多个 collection,一个 collection 可以有多个被邀请者。 m:n 关系。这也意味着我们应该存储贡献用户以及添加到 collection.
  4. 的项目
  5. 然后你想存储点赞。一个用户可以给许多 collection 个项目投票,一个 collection 项目可以被很多用户投票。再次m:n。

我们最终得到这些 table:

  • 用户:ID、姓名、电子邮件...
  • 项目:id、名称、描述...
  • Collection: id, name, author_user_id
  • Collection_Item:id,collection_id,item_id,user_id
  • 被邀请人:collection_id、被邀请人_user_id
  • 点赞:collection_item_id、user_id

使用此数据模型,您可以检查用户是否已受邀参加 collection,然后才允许他们发布商品广告。如果你想让 DBMS 确保这一点,你必须将“受邀者”更改为“贡献者”并将作者自己添加到此 table。然后将 Upvote.user_id 更改为 Upvote.contributor_id 并将外键从“Collection_Item”添加到“Contributor”。

由于您使用的是 Postgres,因此您想要 normalize your tables。用一句话来说,规范化意味着您的列由键表示,整个键,只有键。归一化可以是一个 three-step 过程,但我只展示最终结果。

通常,在数据库中,table 名称是单数的。用户,Collection,项目。此外,使用 table 名称命名您的 ID 字段更容易混淆。它使 join SQL 更易于阅读。

那么让我们从用户开始 table。

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

到目前为止,还不错。所有的列都与用户有关。

接下来我们来看Collection

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

到目前为止,还不错。所有者 ID 是 collection.

所有者的用户 ID

接下来,我们来看Item。

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

到目前为止,还不错。所有的列都与一个项目有关。

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

当您拥有 many-to-many 关系时,您就创建了一个连接点 table。那么让我们创建一个 CollectionItem junction table.

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

其中 Collection项目 ID 是主聚类键。您还有一个关于 (Collection ID、Item ID) 的唯一索引,因此您可以将 collection 拉到一起。您还可以在 (Item ID, Collection ID) 上有一个唯一索引,这样您就可以看到哪些项目在多个 collection 中。

您还有一个关于(Collection ID,Collection项目贡献者 ID)的唯一索引。这允许您查看哪个贡献者(用户)将项目贡献给 collection。此用户 ID 可以是 collections 行中的所有者 ID 或其他贡献者。

看问题 2,我们需要投票 table。投票 table 是连接 collection、项目和选民(用户)的另一个连接点 table。

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

其中投票 ID 是主聚类键,并且您在 (Collection ID、项目 ID、选民 ID) 上有一个唯一索引。您可能还有两个其他唯一索引,具体取决于您是否要按选民或项目对选票进行分组。

编辑添加:

您还需要某种许可 table。

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

其中 Permission ID 是主集群键,并且您在(所有者 ID、贡献者 ID)上有一个唯一索引。您还可以有一个您尚未定义的权限类型,因此我无法将其添加到权限 table。权限类型也将是唯一索引的一部分。

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