структура mysql для комментариев и ответов на комментарии - PullRequest
10 голосов
/ 11 августа 2009

Я уже давно об этом думаю, мне нужен способ добавить ответы на комментарии в базе данных, но я не знаю, как поступить.

Это моя текущая таблица комментариев (мало что говорит, но начало положено):

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", но я не уверен, смогу ли я выбрать все комментарии и ответы на комментарии в одном запросе, и если я добавлю новый столбец с именем "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!"
  }
}

Как мне обработать этот массив для работы с ним, можно ли отделить комментарий от ответов?

Ответы [ 6 ]

5 голосов
/ 11 августа 2009

Если вы хотите, чтобы люди могли отвечать на ответы (т. Е. Иметь иерархию ответов, такую ​​как, например, на форуме сообщений), я бы добавил необязательное поле 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 голосов
/ 14 августа 2009

Я решил добавить столбец parent_id в базу данных, и вместо того, чтобы оставить присоединение к ответам, я просто выбрал все комментарии сразу, чтобы позже отсортировать комментарии и ответы с помощью кода на стороне сервера, вот запрос:

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;
}
3 голосов
/ 11 августа 2009

Добавьте столбец parent_comment_id в таблицу комментариев. Сделайте это необязательно. Когда вы делаете запрос, вы можете присоединить все дочерние комментарии к каждому родителю. В качестве небольшой выборочной денормализации (небольшая избыточность) вы можете убедиться, что topic_id также установлен для дочерних комментариев, что позволяет вам немного проще их извлекать (при условии, что вы собираетесь отображать все дочерние комментарии в основной ветке комментариев а не через меньшие запросы ajax).

Создайте презентацию так, как вам нужно, поместите результаты в memcached (или в плоский файл, или в память ... как бы вы ни кэшировали) и все готово.

1 голос
/ 19 августа 2009

все это хорошо, но что если таблица содержит более миллиона строк? и некоторые комментарии могут быть на расстоянии сотен тысяч строк друг от друга. как будут выполняться эти запросы?

1 голос
/ 12 августа 2009

Похоже, вы работаете с WordPress, добавление parent_comment_id было бы идеальным решением, но не в этом случае.

Во-первых, я не думаю, что изменение базовых таблиц WordPress - это хорошая идея. Во-вторых, вы получите сложный код, который будет ломаться с обновлениями WordPress.

Лучше всего использовать плагин, такой как Интенсивные комментарии

Тем не менее, если вы хотите создать свое собственное решение, я бы сказал, создайте еще одну таблицу для ответов на комментарии. а) Ваша новая таблица будет выглядеть так

`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

б) Вы бы получили их таким образом

$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];
}

в) Теперь в вашем цикле комментариев вы можете получить ответы, подобные этому

foreach (  $replies_by_parent [$parent_id] as $reply ) {            
        echo $reply->comment;
    }
1 голос
/ 11 августа 2009

Ответ на комментарий - это комментарий с родительским идентификатором comment_id. Попробуйте добавить comment_id в качестве поля в таблицу комментариев. То, что вы получите, - это древовидная структура.

Если вы хотите получить целое дерево комментариев, лучше всего использовать вложенный набор (https://wiki.htc.lan/Hierarchy_model). Но это более сложное решение.

Вот еще немного информации из MySQL: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...