我有使用PostgreSQL的ltree模块构建的物化路径树结构.
> id1
> id1.id2
> id1.id2.id3
> id1.id2.id5
> id1.id2.id3.id4 ……等
我当然可以轻松地使用ltree来获取整个树或特定路径/子路径中的所有节点,但是当我这样做时,我自然得到的是很多行(相当于一个节点的数组/切片)结束.. Golang /你使用的任何编程语言)
我所追求的是获取树 – 理想情况下从某个开始和结束路径/点 – 作为一个类似于hieracical的JSON树对象
{
"id": 1,
"path": "1",
"name": "root",
"children": [
{
"id": 2,
"path": "1.2",
"name": "Node 2",
"children": [
{
"id": 3,
"path": "1.2.3",
"name": "Node 3",
"children": [
{
"id": 4,
"path": "1.2.3.4",
"name": "Node 4",
"children": [
]
}
]
},
{
"id": 5,
"path": "1.2.5",
"name": "Node 5",
"children": [
]
}
]
}
]
}
我从线性(非层次)行/数组/切片结果集中知道我当然可以在Golang中爆炸路径并在那里创建必要的业务逻辑来创建这个json,但如果有一个方便的话它肯定会好得多直接用PostgreSQL实现这一目标的方法.
那么你如何在PostgreSQL中输出一个ltree树结构到json – 可能从一个开始到结束的路径?
如果你不知道ltree,我想这个问题可以更多地概括为“Materalized path tree to hierachical json”
此外,我正在玩除了ltree路径之外在所有节点上添加parent_id的想法,因为至少我可以使用递归调用使用该id来获取json我猜…我也是考虑在父id上设置一个触发器来管理路径(保持更新),这取决于父ID发生变化的时间 – 我知道这是另一个问题,但也许你可以告诉我你的意见,关于这一点?
我希望有些天才可以帮助我. 🙂
为方便起见,这里有一个示例创建脚本,可用于节省时间:
CREATE TABLE node
(
id bigserial NOT NULL,
path ltree NOT NULL,
name character varying(255),
CONSTRAINT node_pkey PRIMARY KEY (id)
);
INSERT INTO node (path,name)
VALUES ('1','root');
INSERT INTO node (path,name)
VALUES ('1.2','Node 1');
INSERT INTO node (path,name)
VALUES ('1.2.3','Node 3');
INSERT INTO node (path,name)
VALUES ('1.2.3.4','Node 4');
INSERT INTO node (path,name)
VALUES ('1.2.5','Node 5');
最佳答案 我能够找到并稍微改变它以使用ltree的物化路径而不是像邻接树结构中经常使用的父ID.
虽然我仍然希望有更好的解决方案,但我想这将完成工作.
我觉得除了ltree路径之外我还要添加parent_id,因为这当然不能像引用父ID一样快.
好的信用额去了这个家伙的solution,这是我使用ltree的子路径,ltree2text和nlevel稍微修改过的代码来实现完全相同:
WITH RECURSIVE c AS (
SELECT *, 1 as lvl
FROM node
WHERE id=1
UNION ALL
SELECT node.*, c.lvl + 1 as lvl
FROM node
JOIN c ON ltree2text(subpath(node.path,nlevel(node.path)-2 ,nlevel(node.path))) = CONCAT(subpath(c.path,nlevel(c.path)-1,nlevel(c.path)),'.',node.id)
),
maxlvl AS (
SELECT max(lvl) maxlvl FROM c
),
j AS (
SELECT c.*, json '[]' children
FROM c, maxlvl
WHERE lvl = maxlvl
UNION ALL
SELECT (c).*, json_agg(j) children FROM (
SELECT c, j
FROM j
JOIN c ON ltree2text(subpath(j.path,nlevel(j.path)-2,nlevel(j.path))) = CONCAT(subpath(c.path,nlevel(c.path)-1,nlevel(c.path)),'.',j.id)
) v
GROUP BY v.c
)
SELECT row_to_json(j)::text json_tree
FROM j
WHERE lvl = 1;
但是,这个解决方案存在一个很大的问题,到目前为止..请参阅下面的图片了解错误(节点5丢失):