1

我正在构建一个类似于 Reddit 的评论部分。所以可以有根评论,用户可以回复根评论,然后用户可以回复子评论等等。基本上是嵌套的评论线程。

我使用了本教程并且有点让它工作:

http://www.postgresonline.com/article_pfriendly/173.html

这是我构建表并插入数据并查询它:

CREATE TABLE comments(commentid integer PRIMARY KEY, commentparentid integer, comment varchar(1000), node_path ltree);

CREATE UNIQUE INDEX idx_comments_node_path_btree_idx ON comments USING btree(node_path);
CREATE INDEX idx_comments_node_path_gist_idx ON comments USING gist(node_path);



CREATE OR REPLACE FUNCTION get_calculated_node_path(param_commentid integer)
  RETURNS ltree AS
$$
SELECT  CASE WHEN s.commentparentid IS NULL THEN s.commentid::text::ltree 
            ELSE get_calculated_node_path(s.commentparentid)  || s.commentid::text END
    FROM comments As s
    WHERE s.commentid = $1;
$$
  LANGUAGE sql;


CREATE OR REPLACE FUNCTION trig_update_node_path() RETURNS trigger AS
$$
BEGIN
  IF TG_OP = 'UPDATE' THEN
        IF (COALESCE(OLD.commentparentid,0) != COALESCE(NEW.commentparentid,0)  OR  NEW.commentid != OLD.commentid) THEN
            -- update all nodes that are children of this one including this one
            UPDATE comments SET node_path = get_calculated_node_path(commentid) 
                WHERE OLD.node_path  @> comments.node_path;
        END IF;
  ELSIF TG_OP = 'INSERT' THEN
        UPDATE comments SET node_path = get_calculated_node_path(NEW.commentid) WHERE comments.commentid = NEW.commentid;
  END IF;

  RETURN NEW;
END
$$
LANGUAGE 'plpgsql' VOLATILE;




CREATE TRIGGER trig01_update_node_path AFTER INSERT OR UPDATE OF commentid, commentparentid
   ON comments FOR EACH ROW
   EXECUTE PROCEDURE trig_update_node_path();

INSERT INTO comments(commentid,commentparentid, comment)
VALUES (1, NULL, 'GreatGreatGrandpa'),
(2, NULL, 'GreatGreatGrandma'),
(3,1, 'GreatGrandpa'),
(4,3, 'Grandpa'),
(5,4, 'Pa'),
(6,5, 'Son'),
(7,6, 'Grandson'),
(13,6, 'Grandson2'),
(8,2, 'GreatGrandma'),
(9,8, 'Grandma'),
(10,9, 'Ma'),
(11,10, 'Daughter'),
(12,11, 'GrandDaughter');

SELECT commentid, commentparentid, comment, node_path FROM comments;

这是输出:

commentid | commentparentid |      comment      |   node_path    
-----------+-----------------+-------------------+----------------
         1 |                 | GreatGreatGrandpa | 1
         2 |                 | GreatGreatGrandma | 2
         3 |               1 | GreatGrandpa      | 1.3
         4 |               3 | Grandpa           | 1.3.4
         5 |               4 | Pa                | 1.3.4.5
         6 |               5 | Son               | 1.3.4.5.6
         7 |               6 | Grandson          | 1.3.4.5.6.7
        13 |               6 | Grandson2         | 1.3.4.5.6.13
         8 |               2 | GreatGrandma      | 2.8
         9 |               8 | Grandma           | 2.8.9
        10 |               9 | Ma                | 2.8.9.10
        11 |              10 | Daughter          | 2.8.9.10.11
        12 |              11 | GrandDaughter     | 2.8.9.10.11.12

这是将评论线程作为行获取的查询和输出:

SELECT c.commentid, c.node_path, array_to_string(array_agg(a.comment ORDER BY a.node_path), '->') As comment_fulltree
FROM comments As c INNER JOIN comments As a
    ON (a.node_path @> c.node_path)
GROUP BY c.commentid, c.node_path, c.comment
ORDER BY c.node_path;


 commentid |   node_path    |                           comment_fulltree                            
-----------+----------------+-----------------------------------------------------------------------
         1 | 1              | GreatGreatGrandpa
         3 | 1.3            | GreatGreatGrandpa->GreatGrandpa
         4 | 1.3.4          | GreatGreatGrandpa->GreatGrandpa->Grandpa
         5 | 1.3.4.5        | GreatGreatGrandpa->GreatGrandpa->Grandpa->Pa
         6 | 1.3.4.5.6      | GreatGreatGrandpa->GreatGrandpa->Grandpa->Pa->Son
        13 | 1.3.4.5.6.13   | GreatGreatGrandpa->GreatGrandpa->Grandpa->Pa->Son->Grandson2
         7 | 1.3.4.5.6.7    | GreatGreatGrandpa->GreatGrandpa->Grandpa->Pa->Son->Grandson
         2 | 2              | GreatGreatGrandma
         8 | 2.8            | GreatGreatGrandma->GreatGrandma
         9 | 2.8.9          | GreatGreatGrandma->GreatGrandma->Grandma
        10 | 2.8.9.10       | GreatGreatGrandma->GreatGrandma->Grandma->Ma
        11 | 2.8.9.10.11    | GreatGreatGrandma->GreatGrandma->Grandma->Ma->Daughter
        12 | 2.8.9.10.11.12 | GreatGreatGrandma->GreatGrandma->Grandma->Ma->Daughter->GrandDaughter

这是一个查询和输出,用于获取最底部的叶子评论的路径:

SELECT c.commentid, c.node_path, array_to_string(array_agg(a.comment ORDER BY a.node_path), '-->') As comment_fulltree
FROM (SELECT *
FROM comments AS c1
WHERE NOT EXISTS (
  SELECT *
  FROM comments AS c2
  WHERE c1.node_path @> c2.node_path
    AND c1.node_path <> c2.node_path
)) As c INNER JOIN comments As a
    ON (a.node_path @> c.node_path)
GROUP BY c.commentid, c.node_path, c.comment
ORDER BY c.node_path;

 commentid |   node_path    |                              comment_fulltree                              
-----------+----------------+----------------------------------------------------------------------------
        13 | 1.3.4.5.6.13   | GreatGreatGrandpa-->GreatGrandpa-->Grandpa-->Pa-->Son-->Grandson2
         7 | 1.3.4.5.6.7    | GreatGreatGrandpa-->GreatGrandpa-->Grandpa-->Pa-->Son-->Grandson
        12 | 2.8.9.10.11.12 | GreatGreatGrandma-->GreatGrandma-->Grandma-->Ma-->Daughter-->GrandDaughter

尽管如此,我还是很难思考和弄清楚如何将此输出转换为实际的 HTML 以将注释显示为嵌套线程。

我已经使用 nodejs 和 EJS 视图的组合构建了 HTML,我可以在其中使用嵌套 div 显示嵌套注释。

我也熟悉使用“pg-promise”nodejs 模块来查询数据库。我理解这部分。

但我无法弄清楚如何从数据库中获取输出并将其转换为 HTML。就像现在一样,输出只是告诉我有一个嵌套线程,例如GreatGreatGrandma->GreatGrandma->Grandma->Ma->Daughter->GrandDaughter. 但由于这不是 JSON 或数组,我不确定如何遍历它来构建我的 HTML?

我在想如果有一些 SQL 给我一个嵌套的 JSON,那么我可以构建 HTML。但是不知道怎么获取?

4

1 回答 1

0

我能够解决它。

我使用了以下 SQL:

SELECT nlevel(node_path) as depth, commentid, commentparentid, comment, node_path FROM comments ORDER BY node_path;

这给了我:

depth | commentid | commentparentid |      comment      |   node_path    
--------+-----------+-----------------+-------------------+----------------
      1 |         1 |                 | GreatGreatGrandpa | 1
      2 |         3 |               1 | GreatGrandpa      | 1.3
      3 |         4 |               3 | Grandpa           | 1.3.4
      4 |         5 |               4 | Pa                | 1.3.4.5
      5 |         6 |               5 | Son               | 1.3.4.5.6
      6 |        13 |               6 | Grandson2         | 1.3.4.5.6.13
      6 |         7 |               6 | Grandson          | 1.3.4.5.6.7
      1 |         2 |                 | GreatGreatGrandma | 2
      2 |         8 |               2 | GreatGrandma      | 2.8
      3 |         9 |               8 | Grandma           | 2.8.9
      4 |        10 |               9 | Ma                | 2.8.9.10
      5 |        11 |              10 | Daughter          | 2.8.9.10.11
      6 |        12 |              11 | GrandDaughter     | 2.8.9.10.11.12

使用它,我遍历行并使用该depth字段来添加</div>深度小于前一个项目的深度。这样我就可以创建我需要的 HTML。

于 2019-08-16T08:14:25.533 回答