评论与回复功能的数据库设计(1)--- mongop篇

时间:2024-03-06 22:34:35

 一.评论与回复功能的分析:

1.以掘金的评论为对象开始这篇文章

此文章主要分析的评论回复的场景是和掘金一样的场景,可以实现评论、对评论的回复、对回复的回复。

图片示例:

 

 

 首先此场景统一称为掘金式场景,因为我不知道怎么称呼它,如上图所示的效果,可以分为三种情况:

(1)对文章的评论:直接挂在文章下面;

(2)对用户评论的回复:统一挂在该评论下面,并且直接显示回复内容即可:

 

 

 (3)对用户回复的回复:统一挂在该评论下面,并且在回复内容前面加上回复谁:

 

 

 此时分析下各个子场景:

(1)直接对文章的评论是属于评论,是掘金式场景下的子场景1;

(2)对文章的评论的回复是属于回复,是掘金式场景下的子场景2;

(3)对文章下面的评论的回复的回复,是掘金式场景下的子场景3;

为什么把上面的掘金的评论与回复功能设计成三种子场景呢?直接两种子场景不是更好吗?简单易懂,我的想法是这样的:

如果你只是想设计成1.评论,2.对评论的回复这两种功能,那么直接将评论与回复功能设计成两种子场景即可,因为此时完全是用户对文章的评论及用户对文章评论的回复而已,这种场景很简单。但是事实上,1.我们不仅仅要对文章进行评论,2.我们还要对评论进行回复,3.我们还要对回复进行回复,所以必须分成三种子场景。

二、开始设计掘金式场景的数据库:

开头还是给上一样的一张图:

虽然把掘金式场景设计成三种子场景,但是只有两种内容,即评论与回复,所以我们设计成两个表就好了,一个评论表,一个回复表。

1.分析评论表需要的字段:

开头贴图:

 

 

 1.1、从上面的评论的图示我们可以看到需要展示的数据有6个,实际上3的数据是掘金自定义的,我们舍弃掉,把它并入用户昵称就好,所以评论表至少要有5个字段:

 from_avatar:String,//评论者头像
from_nickname:String,//评论者昵称
 content:String,//评论内容
time:String,//评论的时间
 agree:Number,//

1.2、对1.1的结果再次分析

但实际上,我们如果昵称设计成非唯一的,就是用户昵称可以重复的,即用户1昵称可以取昵称叫hmy666,第二个用户一样也可以去相同的昵称,所以我们还要一个用户id字段(1),这个id是唯一的,就像我们的身份证一样,来给这条评论增加标识。这个id字段在评论中似乎不用也罢,但是将来如果要做一个像知乎一样的统计一个用户这一年发布了几条评论的功能的话,这个字段就不可或缺了。

此外我们还要添加上topic_id(2),topic_type(3)来表示文章的id与文章的类型,因为我们是把评论与回复功能设计成两张表,那么这两张表会记录所有类型文章下面的不同文章的评论与回复数据,如果你要为某种文章类型就单独设计评论表和回复表,那么可以舍弃topic_type字段,比如教育类,新闻类,娱乐类等等这些都单独设计评论表与回复表,但是我们这里只设计成两张表就好了,便于讲解说明。

此时又增加了三个字段。

并且还需要一个comment_id(4)来作为评论内容的id,并且这个id也是唯一的,以便于作为这条评论的唯一身份,将来用户对这个评论点赞时,就可以找到这条评论进行点赞处理,或者删除时可以找到该评论进行删除。所以现在共9个,由于我设计的还要复杂一丢丢,就是评论者的身份可能是普通会员或者VIP会员,那么再增加一个from_status来表示评论者的身份。

所以评论表设计如下:

 comment_id:String,//评论的id【unique唯一值】 
 topic_id:String,//被评论文章id 
  content:String,//评论内容
 topic_type:String,//被评论文章类型
 from_uid:String,//评论者id
from_nickname:String,//评论者昵称
 from_status:String,//评论者的身份
 from_avatar:String,//评论者头像
time:String,//评论的时间
  agree:Number,//

2.分析回复表需要的字段:

开头贴图:

 

 

 2.1首先回复可以分为两种子场景。

2.1.1、子场景1:对评论的回复,此时需要的字段同评论表一样;

2.1.2、子场景2:对回复的回复,增加了一个对谁的回复的字段。其他都与评论表一样。

 

上面分析了只有子场景2多增加了一个对谁回复的字段而已,那么回复表是不是只比评论表多出一个字段而已,需要11个字段就够了?答案是否定的。因为回复表中比较特殊,他需要的某些字段,需要自己一份,另一份还要记录其它人的。比如from_nickname,昵称来记录自己的回复,还要记录对的回复,这个也有昵称。所以需要的字段有些需要两倍,下面给出:

 

rom_nickname--->to_nickname

from_id--->to_uid

from_status--->to_status,所以总共比评论表多增加了4个。总共14个

 reply_id:String,//回复id【unique唯一值】
 topic_id:String,//被评论文章id 
 topic_type:String,//被回复文章类型
  content:String,//评论内容
  from_uid:String,//回复者
 to_uid:String,//被回复者
 from_nickname:String,//回复者昵称
to_nickname:String,//被回复者昵称
  from_status:String,//回复者的身份
 to_status:String,//被回复者的身份
  from_avatar:String,//回复者头像
 to_avatar:String,//被回复者头像
  time:String,//回复的时间
 agree:Number,//

 

2.2、对2.1结果的再次分析

 

 实际上,回复表的设计逻辑比评论表复杂一点,因为评论表只需要无脑插入数据,然后前端渲染只需要无脑请求数据,然后根据对应的文章类型下面的某一篇文章请求对应的评论数据就好。

但是回复表不能只做这些,评论表还需要多做一步,就是当对应文章请求到回复数据后,还要针对对应的评论,插入对应的回复,所以你还需要在回复表中保存评论表的comment_id,用来表示这条回复是针对哪一条具体评论进行的回复。所以增加了第15个字段comment_id。

 

此时你是否认为评论表的所有字段设计完成了,当然,你可以这么认为,针对不同的需求,有不同的设计,但是就像上面说到的,回复中有两个子场景。

对评论回复时直接显示回复内容,对回复的回复时,需要显示对谁的回复,再显示内容:

 

 那么上面两种状态怎么控制呢,很简单增加第16个字段,flag,用于表示此回复是对评论的回复还是对回复的回复,然后再根据flag值在渲染数据时再决定是否显示对某某的回复。

 此时回复表总共16个字段,我就不再贴表格了,因为博客园的编辑器真的太难受了,连复制个表格都会变乱,这里吐槽一下,上次博客园整改之后,我立马找了个代替的平台写博客,找的是思否,思否编辑器就比较现代化,编辑起来比较舒服,虽然分屏显示的时候,插入图片时,如果不换行打字的话,页面会一闪一闪的,很晃眼,但是整体编辑器的感受还是很不错的,要不是博客园的seo优化做的比较好,而且博客园支持不同的文章类型可以进行分类,并且广告较少,可能我会有其他的打算,但是综合考虑两者的优缺点后,我选择博客园和思否一起使用。

 

3、附加功能,点赞:

点赞功能我原本以为可以不用重新建表的,但是要记录每一个用户对某一条评论或者回复是否点了赞,在评论表或者在回复表中寻求思路,我觉得很难,但是如果重新建立一个新的表的话,不同用户的点赞状态就很容易记录:

这个我就不说了,直接贴我的数据库设计的字段,里面注释很清楚,有点累了,先溜了!

//article_comment 评论表
var article_comment_schema = mongoose.Schema({
 comment_id:String,//评论的id【unique唯一值】 --->建索引 以便于删除评论或者点赞时快速找到该评论
  topic_id:String,//被评论文章id --->建索引 以便渲染数据时,根据文章类型加速找到对应的文章
  topic_type:String,//被评论文章类型 --->建索引 以便渲染数据时,找到加速对应的文章类型
  content:String,//评论内容
  from_uid:String,//评论者id
  from_nickname:String,//评论者昵称
  from_status:String,//评论者的身份
  from_avatar:String,//评论者头像
  time:String,//评论的时间
  agree:Number,//
})

//article_reply 回复表
var article_reply_schema = mongoose.Schema({
 comment_id:String,//被回复评论的id,对应的是上面评论表中的comment_id[此时这里的comment_id不是唯一值,因为回复表中可以保存对评论表中的同一个comment_id的多次回复] --->建索引 以便于快速返回每条评论对应的回复,也可以当用户删除评论时快速删除回复表中对该评论的回复
  reply_id:String,//回复id【unique唯一值】--->建索引 以便于删除回复时快速找到该回复
  topic_id:String,//被回复文章id --->建索引 以便渲染数据时,根据文章类型加速找到对应的文章
  topic_type:String,//被回复文章类型 --->建索引 以便渲染数据时,找到加速对应的文章类型
  content:String,//回复内容
  from_uid:String,//回复者
  to_uid:String,//被回复者
  from_nickname:String,//回复者昵称
  to_nickname:String,//被回复者昵称
  from_status:String,//回复者的身份
  to_status:String,//被回复者的身份
  from_avatar:String,//回复者头像
  to_avatar:String,//被回复者头像
  time:String,//回复的时间
  flag:Boolean,//可选值,用于回复时是否要显示对谁的回复
  agree:Number,//
})

//article_agree 点赞表 (schema:概要)
var article_agree_schema = mongoose.Schema({
 from_uid:String,//点赞者 用户登录时这个from_uid指向登录者
  topic_id:String,//被评论文章id --->建索引 以便渲染数据时,根据文章类型加速找到对应的文章
 topic_type:String,//被评论文章类型 --->建索引 以便渲染数据时,找到加速对应的文章类型 --->这个格式又乱了,天哪,博客园团队不可以换个编辑器吗?直接分成两部分了,服了

to_uid:String,//给谁点赞 这个to_uid指向的是各个评论或者回复中的from_uid,也就是说指向的是各条评论或者回复的发布者 comment_or_reply_id:String,//保存每条评论或者回复的唯一id--->建索引 以便于修改点赞时快速找到该记录 由于单单只有from_uid和to_uid不足以记录用户对各条评论或者各条回复的点赞状态;因为客户端渲染时,评论或者回复列表中有多个from_uid和多个to_uid,但是每个from_uid或者to_uid对应的comment_id或者reply_id是唯一的,所以增加该字段;但是由于评论表或者回复表中comment_id或者reply_id都是唯一的,所以只是记录点赞状态的话,上面的from_uid和to_uid不用设置也可以;但是为了见名知意,或者后期可能需要,加上该值也无妨 isAgreeClick:Boolean,//用户点赞状态 这个isAgreeClick表示的是【每条评论或者每条回复中】from_uid对to_uid的点赞状态,保存的都是true,因为只有点赞了才保存到这里,如果用户取消点赞,删除对应的记录即可,这个值用于前端获取设置用户的点赞状态,对用户给予相应的反馈 })