javascript - 如何显示基于赞成票的递归评论?

标签 javascript node.js postgresql recursion recursive-query

我的网站 ( privacyfirstproducts.com ) 上有一个评论部分,我很乐意以这种结构显示评论(就像黑客新闻一样):

comment 1 (10 upvotes)
  comment 4 (reply on comment 1, 7 upvotes)
  comment 5 (reply on comment 1, 5 upvotes)
    comment 8 (reply on comment 5, 8 upvotes)
      ...
  comment 9 (reply on comment 1, 3 upvotes)
  comment 3 (reply on comment 1, 0 upvotes)
  comment 10 (reply on comment 1, 0 upvotes)
  ...
comment 6 (2 upvotes)
  comment 7 (reply on comment 3, 2 upvotes)
comment 2 (0 upvotes)
...

我有这个 postgresql comments-table:

comment_id | original_id | upvotes | text | ...
------------------------------------------------------
         1 |        NULL |      10 | Hi.. | ...
         2 |        NULL |       0 | Je.. | ...
         3 |           1 |       0 | Di.. | ...
         4 |           1 |       7 | Si.. | ...
         5 |           1 |       5 | Op.. | ...
         6 |        NULL |       2 | Op.. | ...
         7 |           6 |       2 | Op.. | ...
         8 |           5 |       8 | Op.. | ...
         9 |           1 |       3 | Op.. | ...
        10 |           1 |       0 | Th.. | ...

我很乐意将其作为 postgresql 的输出:

comment_id | original_id | upvotes | deep | text | ...
------------------------------------------------------
         1 |        NULL |      10 |    0 | Hi.. | ...
         4 |           1 |       7 |    1 | Si.. | ...
         5 |           1 |       5 |    1 | Op.. | ...
         8 |           5 |       8 |    2 | Op.. | ...
         9 |           1 |       3 |    1 | Op.. | ...
         3 |           1 |       0 |    1 | Di.. | ...
        10 |           1 |       0 |    1 | Th.. | ...
         6 |        NULL |       2 |    0 | Op.. | ...
         7 |           6 |       2 |    1 | Op.. | ...
         2 |        NULL |       0 |    0 | Je.. | ...

我认为这应该通过递归来完成,但我不知道该怎么做。

最佳答案

递归查询记录在 CTE 中手册的一部分。

您首先选择根行(在您的例子中,是顶级评论;original_id IS NULL 的评论)。

递归查询的第二部分(在下面示例中的 UNION 之后)将子评论与已经找到的评论连接起来。它会自动重复,直到找不到更多行。在您的情况下,第二个选择需要在 child.original_id = parent.comment_id 上加入 child 对 parent 的评论。

找到每个 Node 的深度很容易 - 只需在进行第二次选择时将父行的深度加 1。

比较棘手的部分是获得您需要的排序顺序(按投票和 ID,保持评论按父组分组)。这可以通过在数组(下例中的 path 列)中累积投票以及每个评论的祖先 ID,然后按数组对行进行排序来完成。请注意,示例中的投票计数已被否定,以便首先对较高的值进行排序。这可以通过对 DESC 进行排序来完成,但是当评论具有相同的票数时,评论 ID 必须取反才能首先对较早的评论进行排序。

WITH RECURSIVE comment_tree AS (
  -- First select performed to get top level rows
  SELECT
     comment_id,
     original_id,
     upvotes,
     text,
     0 depth,                           -- depth in the tree
     ARRAY[-upvotes, comment_id] path   -- used to sort by vote then ID
  FROM comment WHERE original_id IS NULL
  UNION
  -- Self referential select performed repeatedly until no more rows are found
  SELECT
    c.comment_id,
    c.original_id,
    c.upvotes,
    c.text,
    ct.depth + 1,
    ct.path || ARRAY[-c.upvotes, c.comment_id]
  FROM comment c
    JOIN comment_tree ct ON c.original_id = ct.comment_id
)
SELECT * FROM comment_tree ORDER BY path;

关于javascript - 如何显示基于赞成票的递归评论?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53362825/

相关文章:

javascript - 无法在 Sencha-Touch2 中使用 Ext.Ajax 运行 javascript?

javascript - 使用 JavaScript 设置自定义属性

postgresql - 使用postGIS添加点和计算英里距离的正确方法

node.js - 如何将项目从 npm 迁移到 pnpm

node.js - 在 Node.js 中。使用 "request"包可以同时发送多少个请求

postgresql - 性能和从 GUI move 节点的最佳 PostgreSQL 层次树?

PostgreSQL:指定要使用的索引

c# - 将 C# 客户端集成到 node.js + socket.io 聊天应用程序中

javascript - 如何仅在OnInit之后启动iterableDiffer?

javascript - Express 的子域名、重定向和静态文件