Home > OS >  Nested leaf node
Nested leaf node

Time:11-17

I've stored a tree that contains multiple nodes. Every record in that table represents a node and its parent-node, as follows:

node_id parent_id
A null
B A
C A
D B
E B

As a result, the visual tree would look like this: tree-nodes

My goal is to create a function that'll hold the JSON path for every leaf in the tree. So for my current table, the result should behave as shown below:

leaf_id json_path
C {"name": "A", "children": [{ "name": "C", "children": [] }] }
D {"name": "A", "children": [{ "name": "B", "children": [{ "name": "D", "children": [] }] }] }
E {"name": "A", "children": [{ "name": "B", "children": [{ "name": "E", "children": [] }] }] }

There's already a question with a function that does the format I'm trying to achieve (link below): nested-json-object. However, the written function selects the entire tree. Therefore, as I mentioned above, I need the path of every leaf node.

CodePudding user response:

Using a recursive cte:

with recursive cte(id, l, js) as (
   select t.node_id, t.node_id, jsonb_build_object('name', t.node_id, 'children', '[]'::jsonb) from tbl t 
   where not exists (select 1 from tbl t1 where t1.parent_id = t.node_id)
   union all
   select t3.parent_id, t3.l, jsonb_build_object('name', t3.parent_id, 'children', t3.js) 
   from (select t2.parent_id, t2.l, jsonb_agg(t2.js) js  
         from (select t1.parent_id, c.l, c.js from tbl t1 
         join cte c on c.id = t1.node_id) t2 group by t2.parent_id, t2.l) t3
)
select l leaf_id, v json_path from cte 
cross join jsonb_array_elements(js -> 'children') v where id is null

See fiddle

  • Related