【问题标题】:mysql structure for comments and comment replies评论和评论回复的mysql结构
【发布时间】:2009-08-11 14:53:20
【问题描述】:

我已经考虑这个问题已经有一段时间了,我需要一种方法来在数据库中添加对 cme​​ts 的回复,但我不知道如何继续。

这是我目前的评论表(不多说但它是一个开始):

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!"
  }
}

我应该如何处理这个数组以使用它,是否可以将评论与回复分开?

【问题讨论】:

    标签: mysql join


    【解决方案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,稍后使用服务器端代码对 cme​​ts 和回复进行排序,查询如下:

      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' 
        

        【讨论】:

          猜你喜欢
          • 2019-08-07
          • 2018-08-17
          • 1970-01-01
          • 2012-08-23
          • 2010-09-17
          • 2012-02-07
          • 1970-01-01
          • 2020-10-02
          • 1970-01-01
          相关资源
          最近更新 更多