请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

如何实现评论列表以及对评论回复的展示功能

老师,如何实现类似新浪微博或者知乎问答等很常见的评论形式:
展示一级评论,同时展示一级评论下对该评论的回复,如果回复内容较多,同时会展示回复的数量。
图片描述

图片描述

我目前暂定的数据库表结构如下:

图片描述

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for comment_tb
-- ----------------------------
DROP TABLE IF EXISTS `comment_tb`;
CREATE TABLE `comment_tb` (
  `comment_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '评论id',
  `weibo_id` bigint(20) NOT NULL COMMENT '评论的微博id',
  `parent_id` bigint(20) DEFAULT NULL COMMENT '父评论id,如果null代表一级评论',
  `replyto_id` bigint(20) DEFAULT NULL COMMENT '回复的是哪条评论下的评论的id 如果没有,代表是直接回复一级评论',
  `content` varchar(255) NOT NULL COMMENT '评论内容',
  `create_date` datetime NOT NULL,
  PRIMARY KEY (`comment_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

我目前使用的查询SQL如下,只能查询出一级评论:

SELECT `comment_id`,`weibo_id`,`parent_id`,`replyto_id`,`content`,`create_date` FROM comment_tb WHERE weibo_id=XXX GROUP BY parent_id;

求教,该如何写SQL才可以实现这种被广泛使用的评论形式。


问题补充:

在老师的建议下,我采用了两张表的方案。以下是两张表的结构:

comment_item_tb

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for comment_item_tb
-- ----------------------------
DROP TABLE IF EXISTS `comment_item_tb`;
CREATE TABLE `comment_item_tb` (
  `comment_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '评论id',
  `weibo_id` bigint(20) NOT NULL COMMENT '评论的微博id',
  `content` text NOT NULL COMMENT '评论的内容',
  `user_id` bigint(20) NOT NULL COMMENT '评论创建者id',
  `create_date` datetime NOT NULL,
  PRIMARY KEY (`comment_id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4;

reply_item_tb

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for reply_item_tb
-- ----------------------------
DROP TABLE IF EXISTS `reply_item_tb`;
CREATE TABLE `reply_item_tb` (
  `reply_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '回复id',
  `content` text NOT NULL,
  `parent_id` bigint(20) NOT NULL COMMENT '被回复的父级评论id',
  `replyto_id` bigint(20) DEFAULT NULL COMMENT '被回复的其他回复的id,如果没有此项,代表直接回复父级评论内容',
  `user_id` bigint(20) NOT NULL COMMENT'回复创建者id',
  `replied_id` bigint(20) DEFAULT NULL COMMENT '被回复者的用户id,(此项不确定是否需要)',
  `create_date` datetime NOT NULL,
  PRIMARY KEY (`reply_id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4;

另外还有一张用户表user_item_tb 里面存储了用户的username avatar userid等信息

在两张表的前提下,我采用了如下方案

查询50条评论

SELECT
	`comment_id`,
	`content`,
	`weibo_id`,
	`user_id`,
	`username`,
	`avatar`
FROM
	`comment_item_tb`
LEFT JOIN `user_item_tb` ON comment_item_tb.user_id = user_item_tb.uid
WHERE
	`weibo_id` = 1
LIMIT 50;

这样取出了一个符合条件的评论集合,对该集合进行了第一次循环,取出所有的comment_id,然后根据comment_id,我使用了where in 查询

使用where in 语句根据 parent_id 查询

SELECT
	`reply_id`,
	`content`,
	`parent_id`,
	`user_id`,
	`username`,
	`avatar`
FROM
	`reply_item_tb`
LEFT JOIN `user_item_tb` ON reply_item_tb.user_id = user_item_tb.uid
WHERE
	`parent_id` IN (1, 2, 4, 6, 12);

这样取出了所有符合条件的回复结果集合

但是评论集合回复集合在形式上没有关联,我期望的数据形式是类似如下的结构:

{
'comments':[
	{
		'comment_id':123,
		'content':"评论内容",
		'user_id':123,
		'username':'MyName',
		'avatar':'https://avatar.xxx.com/xxx.png',
		'create_date':'2019-10-11 10:10',
		'weibo_id':'xxx',
		//如果没有回复,replies的值为null
		'replies':[
			'reply_id':12345,
			'content':"回复的内容",
			'user_id':12345,
			'username':'MyName',
			'avatar':'https://avatar.xxx.com/xxx.png',
			'replied_userid':'被回复者id',
			'replied_username':'HisName',
			'replied_avatar':'https://avatar.xxx.com/xxx.png',
			'create_date':'2019-10-11 11:11',
		]
	}
]
}

所以我对评论集合和回复集合进行了双层嵌套循环,以下是伪代码:

var comments=[];
commentResult.foreach(item,index){
	comments[index]=item;
	replyResult.foreach(val,key){
		//如果回复的父级id和评论id相同,则为该评论下的回复,添加到回复的replies数组中
		//请忽略没有对replies进行判断的,
		if(val.parent_id==item.comment_id){
			comments[index].replies.push(val);
		}
	}
}

这样需要两层嵌套循环才能得到结果,是否性能低下?

按照以上的方案,确实得到了我需要的评论功能的基本形式,但依然存在三个问题我不知道如何解决。

图片描述

第一个问题:

  • 在第二个SQL中没办法通过left join 查出被回复者的昵称 头像等信息,比如上图的红色区域的被回复者昵称都是假的,因为我不知道如何查询出来

第二个问题:

  • 在第二个SQL中无法查询到每一个评论下的回复总量

第三个问题:

  • 在第二个SQL中没办法限制每一个评论下查询出来的回复总量,比如每个评论我想取出前10条回复,不够的话按实际条数取,然后展示总回复量,点击后继续加载其他回复。现在的SQL没办法做到。

所以还想请教老师指点下,如何实现我想要的功能,业内的通用解决方案是什么样的呢?我看了下,慕课下面的评论和回复也是类似的功能,这应该还算比较常见且常用的功能。


第二次更新:
经过思考,第一个问题已经解决了,只需要继续left join即可,之前我本地不成功的是因为sql报错,在sql语句中有相同表名和字段,所以给表名和字段起个别名, 然后继续left join 即可查出被回复者相关信息,sql如下:

SELECT
	`reply_id`,
	`content`,
	`parent_id`,
	`user_id`,
	usr_tb1.`username`,
	usr_tb1.`avatar`,
	usr_tb2.`username` AS _username,
	usr_tb2.`avatar` AS _avatar
FROM
	`reply_item_tb`
LEFT JOIN `user_item_tb` AS usr_tb1 ON reply_item_tb.user_id = usr_tb1.uid
LEFT JOIN `user_item_tb` AS usr_tb2 ON reply_item_tb.user_id = usr_tb2.uid
WHERE
	`parent_id` IN (1, 2, 4, 6, 12);

所以现在还剩下第二个和第三个问题,继续求解!

正在回答 回答被采纳积分+3

2回答

双越 2019-11-14 20:00:03

我先确认一个问题。你的评论表和回复表,没做外键关联?或者连表查询?

如果有的话,“在第二个SQL中无法查询到每一个评论下的回复总量” —— 这个问题不难解决呀。

0 回复 有任何疑惑可以回复我~
  • 提问者 Attax #1
    确实没做外键关联。用连表查询,需要再单独写一条sql,然后循环评论结果集把回复总量加到相应字段里。我知道这个方案确实可行,但我想知道是否有更好的方案。对于第三个问题,我就实在是没有头绪了
    回复 有任何疑惑可以回复我~ 2019-11-14 23:19:54
  • 双越 回复 提问者 Attax #2
    看问题三,是没办法限制条数。可以考虑加一个字段来做过滤,这个字段即标记该回复是否要显示。
    回复 有任何疑惑可以回复我~ 2019-11-15 08:58:55
双越 2019-11-11 20:24:15

你就一个表?

如果把评论和回复拆成两个表,是不是就简单很多了?试着想一下。

0 回复 有任何疑惑可以回复我~
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信