Структура 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'