我正在构建一个类似于 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。但是不知道怎么获取?