评论和评论回复的mysql结构
Posted
技术标签:
【中文标题】评论和评论回复的mysql结构【英文标题】:mysql structure for comments and comment replies 【发布时间】:2009-08-11 14:53:20 【问题描述】:我已经考虑这个问题已经有一段时间了,我需要一种方法来在数据库中添加对 cmets 的回复,但我不知道如何继续。
这是我目前的评论表(不多说但它是一个开始):
CREATE TABLE IF NOT EXISTS `comments` (
`id` int(12) NOT NULL AUTO_INCREMENT,
`comment` text,
`user_id` int(12) DEFAULT NULL,
`topic_id` int(12) NOT NULL,
`ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `topic_id` (`topic_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=27 ;
这是我当前的查询:
SELECT c.id, c.comment, c.user_id, u.username, u.photo
FROM (comments c)
JOIN users u ON c.user_id = u.id
WHERE c.topic_id = 9
一种选择是创建一个名为“comment_replies”的新表,但我不确定是否能够在一个查询中选择所有 cmets 和评论回复,以及是否添加一个名为“reply”的新列我不知道如何对它们进行排序以在每个回复中获得每条评论。
我很想就如何处理这个问题获得一些建议。
编辑:
按照以下关于添加 parent_comment_id 的答案从 1 条评论和 2 条回复中产生这种数组:
array(2)
[0]=>
object(stdClass)#17 (7)
["id"]=>
string(2) "26"
["comment"]=>
string(36) "adding a comment from the admin page"
["user_id"]=>
string(2) "16"
["ts"]=>
string(10) "1249869350"
["username"]=>
string(5) "Admin"
["photo"]=>
string(13) "gravatar2.png"
["reply"]=>
string(23) "There is no admin page!"
[1]=>
object(stdClass)#18 (7)
["id"]=>
string(2) "26"
["comment"]=>
string(36) "adding a comment from the admin page"
["user_id"]=>
string(2) "16"
["ts"]=>
string(10) "1249869350"
["username"]=>
string(5) "Admin"
["photo"]=>
string(13) "gravatar2.png"
["reply"]=>
string(13) "Yes there is!"
我应该如何处理这个数组以使用它,是否可以将评论与回复分开?
【问题讨论】:
【参考方案1】:如果您希望人们能够回复回复(即具有回复的层次结构,例如您在在线消息论坛中看到的),那么我将在 cmets 表中添加一个可选的 parent_comment_id 字段。
你的桌子应该是这样的
`CREATE TABLE IF NOT EXISTS `comments` (
`id` int(12) NOT NULL AUTO_INCREMENT,
`parent_comment_id` int(12) NULL,
`comment` text,
`user_id` int(12) DEFAULT NULL,
`topic_id` int(12) NOT NULL,
`ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `topic_id` (`topic_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=27 ;`
显示所有 cmets 和回复的查询类似于:
SELECT c.id, c.comment, r.comment as reply, c.user_id, u.username, u.photo
FROM (comments c)
JOIN users u ON c.user_id = u.id
LEFT JOIN comments r ON c.id = r.parent_comment_id
WHERE c.topic_id = 9
但是请注意,使用此查询,您的回复不仅会显示在“回复”列中,还会显示在“评论”列中,作为附加行,每行都有零个或多个回复。
要显示回复评论的用户的用户名,您需要两次加入 users 表(第一次是发布原始评论的用户,第二次是回复的用户)。试试这个查询来显示回复用户的用户名:
SELECT c.id, c.comment, c.user_id, u.username, u.photo, r.comment as reply, r.user_id as reply_user_id,
u2.username as reply_username, u2.photo as reply_photo
FROM (comment c)
JOIN users u ON c.user_id = u.id
LEFT JOIN comments r ON c.id = r.parent_comment_id
JOIN users u2 ON r.user_id = u2.id
WHERE c.topic_id = 9
【讨论】:
我添加了 parent_comment_id 并更改了查询,但我不确定下一步该做什么。假设我有 1 条评论和 2 条回复,这将生成 2 个 cmets,两者将具有相同的评论但回复不同,并且两个回复都将具有第一个 cmets 用户名。我用一个例子编辑了我的主要帖子。 我已经编辑了上面的原始查询,以便显示回复评论的用户的用户名和照片。 看起来不错,但它仍然会输出重复的评论值,如果您对一条评论有多个回复,我是否必须使用服务器端代码更改结果数组以将 cmets 与回复?【参考方案2】:将parent_comment_id
列添加到您的 cmets 表。使其成为可选的。查询时,可以将所有子 cmets 加入每个父节点。作为一些选择性的非规范化(轻微冗余),您可以确保在子 cmets 上也设置了 topic_id
,让您更轻松地拉动它们(假设您要在主评论线程中显示所有子 cmets而不是通过较小的 ajax 请求)。
根据需要构建演示文稿,将结果放入 memcached(或平面文件或内存......但您正在缓存),然后您就设置好了。
【讨论】:
【参考方案3】:我决定在数据库中添加 parent_id 列,而不是左加入回复,我只是一次选择了所有 cmets,稍后使用服务器端代码对 cmets 和回复进行排序,查询如下:
SELECT c.*, u.username, u.photo
FROM (comments c)
JOIN users u ON c.user_id = u.id
WHERE c.topic_id = 9
ORDER BY c.id ASC
现在我将查询结果传递给下面的函数,这样每个回复都会作为一个数组添加到评论数组中,所以基本上它返回一个多维数组。
function sort_comments($ar)
$comments = array();
foreach($ar as $item)
if(is_null($item['parent_id'])) $comments[] = $item;
else
$parent_array = array_search_key($item['parent_id'],$comments,'id');
if($parent_array !== false) $comments[$parent_array]['replies'][] = $item;
return $comments;
【讨论】:
什么是函数array_search_key
- 它不是 php 标准库函数
array_search_key 函数在哪里??它存在于 php 中吗?【参考方案4】:
这看起来一切都很好,但是如果表包含超过一百万行呢?有些 cmets 可能相隔数十万行。这些查询将如何执行?
【讨论】:
是的,但现在不太可能,我认为最好的方法是将它们分成两个不同的表,如果你有这么多的数据要处理。【参考方案5】:评论回复是具有父comment_id 的评论。尝试将 comment_id 作为字段添加到您的 cmets 表中。你会得到一个树状结构。
如果您想检索整个 cmets 树,最好的办法是使用嵌套集 (https://wiki.htc.lan/Hierarchy_model)。但这是一个更复杂的解决方案。
这里有一些来自 mysql 的更多信息:http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
【讨论】:
【参考方案6】:看起来您正在使用 WordPress,添加 parent_comment_id
本来是一个理想的解决方案,但在这种情况下并非如此。
首先,我认为修改 WordPress 基本表不是一个好主意。其次,您最终会得到一个复杂的代码,该代码会因 wordpress 更新而中断。
最好使用像Intense Comments这样的插件
如果您想创建自己的解决方案,我会说创建另一个表格来回复评论。 a) 你的新表应该是这样的
`CREATE TABLE IF NOT EXISTS `comment_replies` (
`id` int(12) NOT NULL AUTO_INCREMENT,
`parent_comment_id` int(12) NULL,
`comment` text,
`user_id` int(12) DEFAULT NULL,
`topic_id` int(12) NOT NULL,
`ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `topic_id` (`topic_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
b) 你会这样获取它们
$comment_ids = array_map( 'intval', array_keys( $comments ) );
sort( $comment_ids );
$comments_id_list = join( ',', $comment_ids );
$query = "SELECT c.id, c.comment, c.user_id, u.username, u.photo
FROM (comment_replies c)
JOIN users u ON c.user_id = u.id
WHERE c.parent_comment_id IN ( $comments_id_list )"
$replies = $wpdb->get_results($query);
$replies_by_parent = array();
foreach ( array_keys( $replies ) as $i )
$replies_by_parent [$replies[$i]->id] = array();
foreach ( array_keys( $replies ) as $i )
$replies_by_parent [$replies[$i]->id][] =& $replies[$i];
c) 现在在您的 cmets 循环中,您可以获得这样的回复
foreach ( $replies_by_parent [$parent_id] as $reply )
echo $reply->comment;
【讨论】:
我不使用wordpress,但解决方案看起来相当不错。我必须更多地研究它,看看它是否最适合我。【参考方案7】:function sort_comments($ar)
$comments = [];
$i=0;
foreach($ar as $co)
if(!empty($co['comment_replyof']))
$comments[$co['comment_replyof']]['replies'] = $co;
else
foreach($co as $c => $o) $comments[$co['comment_id']][$c] = $o;
$i++;
return $comments;
SELECT C.*, U.id,U.fname, U.lname FROM (comment C) JOIN users U ON `enter code here`C.comment_user = U.id where C.comment_content='10'
【讨论】:
以上是关于评论和评论回复的mysql结构的主要内容,如果未能解决你的问题,请参考以下文章
MySql vs NoSql - 社交网络评论和通知数据结构和实现