ホームページ >バックエンド開発 >Golang >Golang はマルチレベルのコメントを実装します

Golang はマルチレベルのコメントを実装します

WBOY
WBOYオリジナル
2023-05-10 12:25:07905ブラウズ

ソーシャル メディアとコンテンツ プラットフォームの台頭により、マルチレベルのコメント システムは、さまざまなプラットフォームがユーザーやコミュニティと対話するための重要な方法になりました。マルチレベルのコメント システムをフロントエンドに実装するのは比較的簡単ですが、バックエンドに実装するのは比較的複雑です。この記事では、golangを使って多段コメントを実装する方法を紹介します。

実装アイデア

複数レベルのコメントは実際にはツリー構造の表示であり、各コメントはノードとして使用できます。マルチレベルレビューシステムは、ツリー構造の基本データ構造であるツリーおよびバイナリツリーを使用して実装できます。この記事では、実装にツリー構造のバイナリ ツリーを使用することを選択します。

バイナリ ツリーのノードは左右 2 つの子ノードで構成され、左のノードは現在のノードの最初の子ノード、右のノードは現在のノードの 2 番目の子ノードです。したがって、コメントを追加するたびに、現在のコメントの親ノードとその左右の子ノードに注意するだけで済みます。

データベース設計

マルチレベルのコメント システムを実装するには、各コメントの親子関係をデータベースに保存する必要があります。一般に、ツリー構造を保存するには 2 つの方法を使用できます。

  1. #複数テーブルの関連付けを使用する
  2. 単一テーブルで自己参照関係を使用する

この記事では、2 番目の方法である、単一のテーブルで自己参照リレーションシップを使用することを選択します。

コメント テーブル (コメント) の構造は次のとおりです。

CREATE TABLE `comment` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `parent_id` int(11) DEFAULT NULL COMMENT '父级评论id',
  `content` varchar(255) DEFAULT NULL COMMENT '评论内容',
  `created_at` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`),
  KEY `parent_id` (`parent_id`),
  CONSTRAINT `comment_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `comment` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='评论表'

上記のテーブル構造において、parent_id は現在のコメントの親ノード ID を表します。現在のコメントが第 1 レベルのコメントである場合、parent_id は null になります。 id は現在のコメントの ID、content はコメントの内容、created_at は作成時刻です。

コードの実装

データベースのリンク

まず、golang でデータベース/sql ドライバーと mysql ドライバーを使用してデータベースにリンクする必要があります:

dsn := "root:123456@tcp(127.0.0.1:3306)/test"
db, err := sql.Open("mysql", dsn)
if err != nil {
   fmt.Printf("mysql connect error %s", err.Error())
   return
}

コメントの挿入

コメントを挿入するときは、現在のコメントを親ノードとして処理するか子ノードとして処理するかを決定する必要があります。

現在のコメントが親ノードとして使用されている場合は、データベースに直接挿入されます。現在のコメントが子ノードの場合は、親ノードの右側のノードを更新する必要があります。

// 添加评论
func AddComment(comment Comment) error {
   if comment.ParentID == 0 {
       _, err := db.Exec("INSERT INTO comment(parent_id, content, created_at) VALUES(?, ?, ?)", nil, comment.Content, comment.CreatedAt)
       if err != nil {
           return err
       }
   } else {
       var rightNode *int
       err := db.QueryRow("SELECT right_node FROM comment WHERE id = ?", comment.ParentID).Scan(&rightNode)
       if err != nil {
           return err
       }
       tx, err := db.Begin()
       if err != nil {
           return err
       }
       // 更新右节点
       _, err = tx.Exec("UPDATE comment SET right_node = right_node + 2 WHERE right_node > ?", rightNode)
       if err != nil {
           tx.Rollback()
           return err
       }
       _, err = tx.Exec("UPDATE comment SET left_node = left_node + 2 WHERE left_node > ?", rightNode)
       if err != nil {
           tx.Rollback()
           return err
       }
       _, err = tx.Exec("INSERT INTO comment(parent_id, left_node, right_node, content, created_at) VALUES(?, ?, ?, ?, ?)", comment.ParentID, rightNode, rightNode+1, comment.Content, comment.CreatedAt)
       if err != nil {
           tx.Rollback()
           return err
       }
       tx.Commit()
   }
   return nil
}

コメントのクエリ

コメントをクエリするときは、ノードを左と右の順序で並べ替えて、ツリー構造のコメント リストを取得する必要があります。コメントをクエリする場合、ソートに左右のノードを使用する必要があるため、クエリ条件に左右のノード列を追加する必要があります。さらに、フロントエンド表示を容易にするために、レベル フィールドを使用して現在のノードがノードのどのレベルであるかを示す必要もあります。

type Comment struct {
   ID        int    `json:"id"`
   ParentID  int    `json:"parent_id"`
   Content   string `json:"content"`
   LeftNode  int    `json:"left_node"`
   RightNode int    `json:"right_node"`
   Level     int    `json:"level"`
   CreatedAt string `json:"created_at"`
}

// 获取评论列表
func GetComments() ([]Comment, error) {
   rows, err := db.Query("SELECT id, parent_id, content, created_at, left_node, right_node, (COUNT (parent.id) -1) AS level FROM comment AS node, comment AS parent WHERE node.left_node BETWEEN parent.left_node AND parent.right_node GROUP BY node.id ORDER BY left_node")
   if err != nil {
       return nil, err
   }
   defer rows.Close()

   var comments []Comment
   for rows.Next() {
       var comment Comment
       err := rows.Scan(&comment.ID, &comment.ParentID, &comment.Content, &comment.CreatedAt, &comment.LeftNode, &comment.RightNode, &comment.Level)
       if err != nil {
           return nil, err
       }
       comments = append(comments, comment)
   }
   return comments, nil
}

コメントの削除

コメントを削除するときは、現在のコメントが親ノードであるか子ノードであるかを判断する必要があります。親ノードの場合は、コメント全体を削除する必要があります。サブツリー。

// 删除评论
func DeleteComment(id int) error {
   tx, err := db.Begin()
   if err != nil {
       return err
   }
   var leftNode int
   var rightNode int
   err = tx.QueryRow("SELECT left_node, right_node FROM comment WHERE id = ?", id).Scan(&leftNode, &rightNode)
   if err != nil {
       tx.Rollback()
       return err
   }
   if leftNode == 1 && rightNode > 1 {
       // 删除子树
       _, err = tx.Exec("DELETE FROM comment WHERE left_node >= ? AND right_node <= ?;", leftNode, rightNode)
       if err != nil {
           tx.Rollback()
           return err
       }
       err = tx.Commit()
       if err != nil {
           tx.Rollback()
           return err
       }
   } else {
       // 删除单个节点
       _, err = tx.Exec("DELETE FROM comment WHERE id = ?", id)
       if err != nil {
           tx.Rollback()
           return err
       }
       err = tx.Commit()
       if err != nil {
           tx.Rollback()
           return err
       }
   }
   return nil
}

結論

上記のコード実装を通じて、完全に機能するマルチレベル コメント システムを迅速に構築できます。もちろん、これは基本的な実装方法にすぎず、実際のシナリオでは、特定のニーズに応じて対応する最適化や拡張を行う必要があります。

以上がGolang はマルチレベルのコメントを実装しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。