Структура mysql для комментариев и комментариев
Я уже давно думаю об этом, мне нужен способ добавить ответы на комментарии в базе данных, но я не уверен, как это сделать.
Это моя таблица комментариев в данный момент (много не говорит, но ее начало):
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", но я не уверен. Если я могу выбрать все комментарии и комментарии в одном запросе, и если я добавлю новый столбец "ответ", Я не уверен, как сортировать их, чтобы получать каждый комментарий с каждым ответом.
Я хотел бы получить совет относительно того, как с этим бороться.
Edit:
Следуя приведенным ниже ответам о добавлении 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
Я решил добавить столбец parent_id в базу данных и вместо того, чтобы присоединиться к ответам, я только что выбрал все комментарии сразу, чтобы позже сортировать комментарии и ответы с помощью серверного кода, heres запрос:
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;
}
Ответ 2
Если вы хотите, чтобы люди могли отвечать на ответы (т.е. иметь иерархию ответов, например, вы видели бы, например, форум онлайн-сообщений), я бы добавил необязательное поле 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 ;`
Ваш запрос, показывающий все комментарии и ответы, будет выглядеть примерно так:
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
Обратите внимание, однако, что в этом запросе ваши ответы также будут отображаться не только в столбце "ответ", но также в столбце "комментарий" в виде дополнительных строк с нулевым или большим количеством ответов.
Чтобы показать имя пользователя, ответившего на комментарий, вам нужно будет дважды присоединиться к таблице пользователей (сначала для пользователя, разместившего исходный комментарий, и снова для пользователей, которые ответили). Попробуйте этот запрос, чтобы показать имена пользователей, которые ответили:
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
Ответ 3
Добавьте столбец parent_comment_id
в таблицу комментариев. Сделайте это необязательным. Когда вы запрашиваете, вы можете присоединить все дочерние комментарии к каждому родителю. Как небольшая выборочная денормализация (небольшая избыточность) вы можете убедиться, что topic_id
также установлен на дочерние комментарии, позволяя вам немного потянуть их (предполагая, что вы собираетесь отображать все дочерние комментарии в основной ветке комментариев а не через меньшие запросы ajax).
Постройте презентацию, но вам нужно, забросить результаты в memcached (или плоский файл или память... но вы кешируете), и вы настроены.
Ответ 4
Комментарий комментария - комментарий с родительским комментарием. Попробуйте добавить comment_id в качестве поля в таблицу комментариев. Что вы получите, это древовидная структура.
Если вы хотите получить полное дерево комментариев, лучше всего использовать вложенный набор (https://wiki.htc.lan/Hierarchy_model). Но это более сложное решение.
Вот еще информация от MySQL: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
Ответ 5
Похоже, вы работаете с WordPress, добавив parent_comment_id
было бы идеальным решением, но не в этом случае.
Во-первых, я не думаю, что изменение основных таблиц WordPress - хорошая идея. Во-вторых, вы получите сложный код, который будет разорваться с обновлениями wordpress.
Лучше использовать плагин, например Интенсивные комментарии
Если вы хотите создать собственное решение, я бы сказал, создайте еще одну таблицу для комментариев.
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) Теперь в пределах цикла комментариев вы можете получить ответы, подобные этому
foreach ( $replies_by_parent [$parent_id] as $reply ) {
echo $reply->comment;
}
Ответ 6
Кажется, все хорошо, но как насчет таблицы, содержащей более миллиона строк? и некоторые комментарии могут составлять сотни тысяч строк. как эти запросы будут выполняться?
Ответ 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'