【问题标题】:Returning adjacency list as nested JSON in Postgres在 Postgres 中将邻接列表作为嵌套 JSON 返回
【发布时间】:2016-10-05 10:25:54
【问题描述】:

给定一个两列 Postgres 表(id​​、parent_id)的最简单基本情况,有没有办法查询一个 id 并以嵌套 json 结构取回所有子级,如下所示?

{
    "id": 1,
    "children": [{
        "id": 2,
        "children": [{
            "id": 3,
            "children": []
        }]
    }]
}

我了解如何通过表进行递归,但我无法拼凑出如何使用任何 psql json 函数来返回如上所示的结果。也许我应该只使用我选择的语言在后处理中进行转换?

SQLFiddle 当前进度。

【问题讨论】:

    标签: json postgresql recursion adjacency-list


    【解决方案1】:

    太难了,花了我几个小时才解决:-P

    WITH RECURSIVE 
      tree AS (
        SELECT 1 AS round, id, parent_id, ARRAY(SELECT id FROM foo WHERE parent_id = f.id) AS children
        FROM foo f
        WHERE id = 1
        UNION ALL
        SELECT round+1, f.id, f.parent_id, ARRAY(SELECT id FROM foo WHERE parent_id = f.id) AS children
        FROM tree t
        JOIN foo f ON (f.id = ANY(t.children))
        ),
      rev AS (
        SELECT r.round-1 AS round,
               to_jsonb(ARRAY(
                        SELECT a
                        FROM (
                          SELECT f.parent_id AS id, json_agg(jsonb_build_object('id', f.id, 'children', '{}'::text[])) AS children
                          FROM tree t
                          JOIN foo f ON (f.id = t.id)
                          WHERE t.round = r.round
                          GROUP BY f.parent_id
                          ) a
                        )) AS list
        FROM (SELECT MAX(round)::int AS round FROM tree) r
        UNION ALL
        SELECT r.round-1,
               to_jsonb(ARRAY(
                        SELECT a
                        FROM (
                          SELECT f.parent_id AS id, json_agg(jsonb_build_object('id', f.id, 'children', t->'children')) AS children
                          FROM jsonb_array_elements(list) t
                          JOIN foo f ON (f.id = (t->>'id')::int)
                          GROUP BY f.parent_id
                          ) a
                        )) AS list
        FROM rev r
        WHERE round > 1
        )
    SELECT list as nested_json_tree
    FROM rev
    WHERE round = 1
    

    复杂性在于要求首先构建树(自上而下),然后从树中构建对象,自下而上。由于递归查询的限制,递归自下而上是棘手的,例如 UNION ALL 部分中的递归别名不能被分组,也不能包含在子查询中。我通过倒转解包解决了这个问题。

    这个查询应该正确构建复杂的树,每个节点有多个子节点,嵌套层数不限。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-22
      • 2020-09-28
      • 2019-01-27
      • 2023-04-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多