老师,如何实现类似新浪微博或者知乎问答等很常见的评论形式:
展示一级评论,同时展示一级评论下对该评论的回复,如果回复内容较多,同时会展示回复的数量。
我目前暂定的数据库表结构如下:
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);
}
}
}
这样需要两层嵌套循环才能得到结果,是否性能低下?
按照以上的方案,确实得到了我需要的评论功能的基本形式,但依然存在三个问题我不知道如何解决。
第一个问题:
第二个问题:
第三个问题:
所以还想请教老师指点下,如何实现我想要的功能,业内的通用解决方案是什么样的呢?我看了下,慕课下面的评论和回复也是类似的功能,这应该还算比较常见且常用的功能。
第二次更新:
经过思考,第一个问题已经解决了,只需要继续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);
所以现在还剩下第二个和第三个问题,继续求解!