Postgres LTREE 按 parents 和 children 分组显示

Postgres LTREE display by grouping parents and children

我有一个示例 Ltree 结构,我想 return 它作为 JSON 结构。 我尝试搜索堆栈溢出,但结果给出了错误的响应。

create table node
(
    id   integer not null,
    name varchar(255),
    path ltree   not null
);

我有这些数据

INSERT INTO node (id,name,path) VALUES (1,'Residential','1');
INSERT INTO node (id,name,path) VALUES (2,'Commercial','2');
INSERT INTO node (id,name,path) VALUES (3,'Industrial','3');
INSERT INTO node (id,name,path) VALUES (4,'Res type 1','1.4');
INSERT INTO node (id,name,path) VALUES (5,'Comm type 1','2.5');
INSERT INTO node (id,name,path) VALUES (6,'Industrial 1','3.6');
INSERT INTO node (id,name,path) VALUES (7,'Residential 2','1.4.7');
INSERT INTO node (id,name,path) VALUES (8,'Commercial 2','2.5.8');
INSERT INTO node (id,name,path) VALUES (9,'Industrial 2','3.6.9');

这就是我想通过查询收集的内容

[
  {
    "name": "Residentioal",
    "children": [
      {
        "name": "Res type 1",
        "children": [
          {
            "name": "Residential 2",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "name": "Commercial",
    "children": [
      {
        "name": "Comm type 1",
        "children": [
          {
            "name": "Commercial 2",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "name": "Industrial",
    "children": [
      {
        "name": "Industrial 1",
        "children": [
          {
            "name": "Industrial 2",
            "children": []
          }
        ]
      }
    ]
  }
]

我试过 recursive with .. 但它一直在循环,但没有 return 正确的值。

您需要两部分,递归部分和函数。我已经对此进行了解释 , and ,所以请查看那里以获得进一步的解释。

demo:db<>fiddle

递归

WITH RECURSIVE cte AS (
    SELECT 
        id,
        name,
        path,
        json_build_object('name', name, 'children', ARRAY[]::text[]) AS jsonobject,
        ARRAY[]::text[] || (row_number() OVER () - 1)::text as jsonpath,
        0 as depth        
    FROM node
    WHERE path = subpath(path, 0, 1) --parents

    UNION ALL

    SELECT
        n.id, 
        n.name, 
        n.path,
        json_build_object('name', n.name, 'children', ARRAY[]::text[]),
        jsonpath || '{children}' || (row_number() OVER (PARTITION BY subpath(n.path, depth, 1)::text ORDER BY subpath(n.path, depth + 1, 1)::text::int) - 1)::text,
        c.depth + 1
    FROM
        node n
    JOIN cte c 
    ON c.id = subpath(n.path, depth, 1)::text::int
       AND nlevel(n.path) = depth + 2 AND subpath(n.path, depth + 1, 1)::text::int = n.id
)
SELECT * FROM cte

函数

CREATE OR REPLACE FUNCTION nested_json() RETURNS jsonb AS $$
DECLARE
    _json_output jsonb;
    _temprow record;
BEGIN   
    _json_output := '[]'::jsonb;

    FOR _temprow IN
        -- <Add the CTE from above here>
    LOOP
        SELECT 
        jsonb_insert(
            _json_output, 
            _temprow.jsonpath, 
            _temprow.jsonobject
        )
        INTO _json_output;
    END LOOP;   

    RETURN _json_output;
END;
$$ LANGUAGE plpgsql;

请注意:ltree 结构对于这个用例来说并不是一个很好的选择,因为您需要一次又一次地计算子路径。对父级的简单引用会更有帮助和更快。


编辑: db<>fiddle 管理员很棒,安装了 ltree 扩展,所以有一个新的 fiddle