PostgreSQL 9.3->来自嵌套集的JSON->jQuery listview
我有这个嵌套集:PostgreSQL 9.3->来自嵌套集的JSON->jQuery listview,jquery,json,postgresql,Jquery,Json,Postgresql,我有这个嵌套集: id;parent;name;lft;rgt ---------------------- 1;0;"Food";2;21 3;1;"Appetizer";3;8 8;3;"Nachos & salsa";4;5 9;3;"Kentucky chicken wings";6;7 4;1;"Soup";9;14 10;4;"Broth";10;11 11;4;"Tomato soup";12;13 5;1;"Pizza";15;20 12;5;"Americana";16
id;parent;name;lft;rgt
----------------------
1;0;"Food";2;21
3;1;"Appetizer";3;8
8;3;"Nachos & salsa";4;5
9;3;"Kentucky chicken wings";6;7
4;1;"Soup";9;14
10;4;"Broth";10;11
11;4;"Tomato soup";12;13
5;1;"Pizza";15;20
12;5;"Americana";16;17
13;5;"Margherita";18;19
2;0;"Beverages";22;27
6;2;"Wines";23;24
7;2;"Soft drinks";25;26
我想要一个代表完整树的JSON输出。
我想从JSON构建一个嵌套列表,如下所示:
谢谢你的帮助 要做的第一件事是以可以检索树的方式查询行。为此,我们可以简单地使用递归查询。假设您的表名为food,下面的查询是一个很好的递归查询示例:
WITH RECURSIVE t AS (
SELECT f.id, f.name, f.parent, f.lft, f.rgt, array[f.name] AS path, 0 AS level
FROM food f
WHERE f.parent = 0
UNION ALL
SELECT f.id, f.name, f.parent, f.lft, f.rgt, t.path || f.name, level+1
FROM food f JOIN t ON f.parent = t.id
)
SELECT repeat('|__', level)||t.name AS tree, level, path
FROM t
ORDER BY path;
将以以下形式返回:
tree | level | path
------------------------------+-------+-------------------------------------------
Beverages | 0 | {Beverages}
|__Soft drinks | 1 | {Beverages,"Soft drinks"}
|__Wines | 1 | {Beverages,Wines}
Food | 0 | {Food}
|__Appetizer | 1 | {Food,Appetizer}
|__|__Kentucky chicken wings | 2 | {Food,Appetizer,"Kentucky chicken wings"}
|__|__Nachos & salsa | 2 | {Food,Appetizer,"Nachos & salsa"}
|__Pizza | 1 | {Food,Pizza}
|__|__Americana | 2 | {Food,Pizza,Americana}
|__|__Margherita | 2 | {Food,Pizza,Margherita}
|__Soup | 1 | {Food,Soup}
|__|__Broth | 2 | {Food,Soup,Broth}
|__|__Tomato soup | 2 | {Food,Soup,"Tomato soup"}
(13 rows)
基本上,path数组将给我们一个元素来对行进行排序,这样我们就可以根据需要使用除名称以外的其他列的树,而level基本上是path length-1,它为我们提供了元素所在的级别。有了这两个信息,我们可以使用with窗口ORDER BY path的一些技巧,在每一行查看下一行的级别,从而创建json检查查询中的注释:
WITH RECURSIVE t AS (
SELECT f.id, f.name, f.parent, f.lft, f.rgt, array[f.name] AS path, 0 AS level
FROM food f
WHERE f.parent = 0
UNION ALL
SELECT f.id, f.name, f.parent, f.lft, f.rgt, t.path || f.name, level+1
FROM food f JOIN t ON f.parent = t.id
)
SELECT (E'[\n'||string_agg(json, E'\n')||E'\n]')::json FROM (
SELECT
/* Add some simple indentation (why not?) */
repeat(' ', level)
|| '{"name":'||to_json(name)|| ', "items":['
||
/* The expr bellow will return the level of next row, or -1 if it is last */
CASE coalesce(lead(level) OVER(ORDER BY path), -1)
/* Next row opens a new level, so let's add the items array */
WHEN level+1 THEN ''
/* WHEN level+1 THEN ', "items":[' */
/* We are on the same level, so just close the current element */
WHEN level THEN ']},'
/* Last row, close the current element and all other levels still opened (no indentation here, sorry) */
WHEN -1 THEN ']}' || repeat(']}', level)
/* ELSE, the next one belongs to another parent, just close me and my parent */
ELSE /* closes me: */ ']}' /* closes my parent: */ || E'\n'||repeat(' ', level-1)||']},'
END AS json
FROM t
) s1;
这将为我们提供以下json:
[
{"name":"Beverages", "items":[
{"name":"Soft drinks", "items":[]},
{"name":"Wines", "items":[]}
]},
{"name":"Food", "items":[
{"name":"Appetizer", "items":[
{"name":"Kentucky chicken wings", "items":[]},
{"name":"Nachos & salsa", "items":[]}
]},
{"name":"Pizza", "items":[
{"name":"Americana", "items":[]},
{"name":"Margherita", "items":[]}
]},
{"name":"Soup", "items":[
{"name":"Broth", "items":[]},
{"name":"Tomato soup", "items":[]}]}]}
]
这是一个有点诡计的查询,我希望注释会有所帮助,也希望它对任何测试用例都是正确的。对不起,但是我在使用下一个结构时遇到了一些问题
1,0,'Food',2,21
2,0,'Beverages',22,27
3,1,'Appetizer',3,8
4,3,'Soup',9,14 -- Parent soup is 3 instead 1
5,1,'Pizza',15,20
6,2,'Wines',23,24
7,2,'Soft drinks',25,26
8,3,'Nachos & salsa',4,5
9,3,'Kentucky chicken wings',6,7
10,4,'Broth',10,11
11,4,'Tomato soup',12,13
12,5,'Americana',16,17
13,5,'Margherita',18,19
结果:
tree | level | path
------------------------------+-------+-------------------------------------------
Beverages | 0 | {Beverages}
|__Soft drinks | 1 | {Beverages,"Soft drinks"}
|__Wines | 1 | {Beverages,Wines}
Food | 0 | {Food}
|__Appetizer | 1 | {Food,Appetizer}
|__|__Kentucky chicken wings | 2 | {Food,Appetizer,"Kentucky chicken wings"}
|__|__Nachos & salsa | 2 | {Food,Appetizer,"Nachos & salsa"}
|__|__Soup | 2 | {Food,Appetizer,Soup}
|__|__|__Broth | 2 | {Food,Appetizer,Soup,Broth}
|__|__|__Tomato soup | 3 | {Food,Appetizer,Soup,"Tomato soup"}
|__Pizza | 1 | {Food,Pizza}
|__|__Americana | 2 | {Food,Pizza,Americana}
|__|__Margherita | 2 | {Food,Pizza,Margherita}
(13 rows)
使用相同的逻辑,这可能会更好:
WITH RECURSIVE t AS (
SELECT f.id, f.name, f.parent, f.lft, f.rgt, array[f.name] AS path, 0 AS level
FROM food f
WHERE f.parent = 0
UNION ALL
SELECT f.id, f.name, f.parent, f.lft, f.rgt, t.path || f.name, level+1
FROM food f JOIN t ON f.parent = t.id
)
SELECT ( '[' || string_agg( json, '' ) || ']' ) :: json FROM (
select
'{"name":'||to_json( name ) ||
case lead( level, 1 ) OVER( ORDER BY path )
when level then '},' --same lavel, no children, only close
when level + 1 THEN ', "items":[' -- There's children, add item array
else -- last child in group start to close
'}' || --close actual element
case
when lead( level ) OVER( ORDER BY path ) < level THEN -- last children in group, close parents, until next level
repeat( ']}', level - lead( level ) OVER( ORDER BY path ) ) || ','
else repeat( ']}', level ) -- last element in list, close parents all levels
end
end as json
from t
) s1;
压痕???也许以后
编辑
加小提琴
谢谢,我对查询做了一点修改,[]不需要,可以正常工作。