在数据库中实现评论和喜欢

Kok*_*kos 127 mysql database database-design design-patterns

我是一名软件开发人员.我喜欢编码,但我讨厌数据库...目前,我正在创建一个网站,允许用户将实体标记为喜欢(如FB),标记评论.

我被困在数据库表设计上来处理这个功能.解决方案是微不足道的,如果我们只能为一种类型的东西(例如照片)做到这一点.但我需要为5种不同的东西启用它(现在,但我也假设随着整个服务的增长,这个数字会增长).

我在这里发现了一些类似的问题,但没有一个问题得到满意的答案,所以我再次提出这个问题.

问题是,如何正确,高效弹性地设计数据库,以便它可以存储不同表的注释,喜欢不同的标签.一些设计模式作为答案将是最好的;)

详细描述:我有一个 User与一些用户数据,以及3个:Photo照片,Articles文章,Places的地方.我想启用任何已登录的用户:

  • 评论这3个表中的任何一个

  • 将其中任何一个标记为喜欢

  • 使用某个标记标记其中任何一个

  • 我还想计算每个元素的喜欢次数以及使用特定标记的次数.

1 的做法:

a)对于标签,我将创建一个 Tag [TagId, tagName, tagCounter],然后我会创造很多一对多的关系为:Photo_has_tags,Place_has_tag,Article_has_tag.

b)同样重要的评论.

三)我将创建一个 LikedPhotos [idUser, idPhoto],LikedArticles[idUser, idArticle],LikedPlace [idUser, idPlace].喜欢的数量将通过查询计算(我认为这是坏的).和...

我真的不喜欢这个设计的最后一部分,它对我来说很难闻;)


2 的方法:

我将创建一个表ElementType [idType, TypeName == some table name],该表将由管理员(我)填充,其中包含可以被喜欢,评论标记的名称.然后我将创建:

a)LikedElement [idLike, idUser, idElementType, idLikedElement]和注释和标签相同,每个都有适当的列.现在,当我想拍照时,我会插入:

typeId = SELECT id FROM ElementType WHERE TypeName == 'Photo'
INSERT (user id, typeId, photoId)
Run Code Online (Sandbox Code Playgroud)

和地方:

typeId = SELECT id FROM ElementType WHERE TypeName == 'Place'
INSERT (user id, typeId, placeId)
Run Code Online (Sandbox Code Playgroud)

......等等......我认为第二种方法更好,但我觉得这个设计中也缺少一些东西......

最后,我还想知道哪个最好的地方存放计数器元素被喜欢多少次.我只能想到两种方式:

  1. 在element(Photo/Article/Place)表中
  2. 通过select count().

我希望我对这个问题的解释现在更彻底.

Bra*_*vic 173

最具扩展性的解决方案是只有一个"基础"表(连接到"喜欢",标签和注释),并"继承"其中的所有其他表.添加一种新的实体只需添加一个新的"继承"表 - 然后它会自动插入整个like/tag/comment机器.

实体关系术语是"类别"(参见 ERwin方法指南,部分:"子类型关系").类别符号是:

类别

假设用户可以喜欢多个实体,同一个标签可以用于多个实体,但注释是特定于实体的,您的模型可能如下所示:

ER图


顺便说一下,实施"ER类别"大致有3种方式:

  • 所有类型都在一个表中.
  • 所有具体类型在单独的表中.
  • 所有具体和抽象类型在单独的表中.

除非您有非常严格的性能要求,否则第三种方法可能是最好的(意味着物理表与上图中的实体1:1匹配).

  • @Orion`BIGINT`的最大值是9223372036854775807.假设你每秒插入一行,你将在大约3000亿年后用完可用值.当然,到那时你将能够移植到128位整数! (3认同)
  • 很好的答案,谢谢.我希望,我会设法实现它......我想知道Django ORM将如何处理它(或者我将如何自己做...但是,这是另一个问题;)但是,你能解释一下吗?我,因为我认为我不理解它 - 你为我画的(谢谢!)是你提到的第三种方法? (2认同)
  • @Kokos本质上,方法(3)表示ENTITY是一个表,PHOTO是一个表,ARTICLE是一个表,PLACE是一个表。方法(2)表示没有ENTITY表,而方法(1)则只有一个表。所有这些方法(各有优缺点)的存在是不幸的结果,因为典型的RDBMS本身并不支持表继承。 (2认同)
  • @BrankoDimitrijevic为什么不能将实体表Photo,Article,Place有自己的PK,例如PhotoID,ArticleID等,还有另一列Entity_ID作为FK?这不必要吗? (2认同)

wal*_*lyk 22

既然你"讨厌"数据库,你为什么要尝试实现一个?相反,向喜欢和呼吸这些东西的人寻求帮助.

否则,学会爱你的数据库.精心设计的数据库简化了编程,设计网站并平滑其持续运营.即使是经验丰富的d/b设计师也不会有完整和完美的远见:随着使用模式的出现或需求的变化,将需要一些架构变化.

如果这是一个单人项目,则使用存储过程将数据库接口编程为简单操作:add_user,update_user,add_comment,add_like,upload_photo,list_comments等.不要将模式嵌入到一行代码中.通过这种方式,可以在不影响任何代码的情况下更改数据库模式:只有存储过程应该知道模式.

您可能需要多次重构架构.这个是正常的.不要担心第一次完美.只需使其功能足以原型化初始设计.如果您有足够的时间,请使用它,然后删除架构并再次执行.它总是更好的第二次.

  • 我爱你的最后一句话 - *第二次总是好一点.* (5认同)
  • 不能这样做:学会爱你的数据库 (3认同)
  • 因为我需要自己实施.至少现在......而且,我认为这可能是一个开始喜欢数据库的好时机;)感谢您对存储过程的建议.有人知道,如果它们是由Django ORM自动映射的吗? (2认同)
  • 第二次总是好一些.对 (2认同)

小智 19

这是一个普遍的想法请不要太注意字段名称样式,但更多的是关系和结构

在此输入图像描述

这个伪代码将获得照片的所有注释ID 5
SELECT*FROM actions
WHERE actions.id_Stuff = 5
AND actions.typeStuff ="photo"
AND actions.typeAction ="comment"

这个伪代码将获得喜欢ID为5的照片的所有喜欢或用户
(您可以使用count()来获得喜欢的数量)

SELECT * FROM actions  
WHERE actions.id_Stuff = 5  
AND actions.typeStuff="photo"  
AND actions.typeAction = "like"  
Run Code Online (Sandbox Code Playgroud)

  • `id_stuff`列如何在三个表中的每一个中包含唯一值? (4认同)
  • 如果以这种方式实现点赞,则通知用户新点赞变得更加困难。它需要另一张桌子。 (2认同)