WITH RECURSIVE
का उपयोग करना (https://www.postgresql.org/docs/current/static/queries-with.html) और JSON फंक्शन्स (https://www.postgresql.org/docs/current/static/functions-json.html) I इस समाधान का निर्माण करें:
डीबी<>बेला
मुख्य कार्यक्षमता:
WITH RECURSIVE tree(node_id, ancestor, child, path, json) AS (
SELECT
t1.node_id,
NULL::int,
t2.node_id,
'{children}'::text[] ||
(row_number() OVER (PARTITION BY t1.node_id ORDER BY t2.node_id) - 1)::text,-- C
jsonb_build_object('name', t2.name, 'children', array_to_json(ARRAY[]::int[])) -- B
FROM test t1
LEFT JOIN test t2 ON t1.node_id = t2.parent_node -- A
WHERE t1.parent_node IS NULL
UNION
SELECT
t1.node_id,
t1.parent_node,
t2.node_id,
tree.path || '{children}' || (row_number() OVER (PARTITION BY t1.node_id ORDER BY t2.node_id) - 1)::text,
jsonb_build_object('name', t2.name, 'children', array_to_json(ARRAY[]::int[]))
FROM test t1
LEFT JOIN test t2 ON t1.node_id = t2.parent_node
INNER JOIN tree ON (t1.node_id = tree.child)
WHERE t1.parent_node = tree.node_id -- D
)
SELECT -- E
child as node_id, path, json
FROM tree
WHERE child IS NOT NULL ORDER BY path
प्रत्येक WITH RECURSIVE
एक प्रारंभ होता है SELECT
और एक रिकर्सन भाग (दूसरा SELECT
) एक UNION
. द्वारा संयुक्त .
उ:node_id
. के बच्चों को खोजने के लिए तालिका में फिर से शामिल होना .
बी:बच्चे के लिए जेसन ऑब्जेक्ट बनाना जिसे उसके माता-पिता में डाला जा सकता है
सी:पथ का निर्माण जहां बच्चे की वस्तु डाली जानी है (रूट से)। विंडो फ़ंक्शन row_number()
(https://www.postgresql.org/docs/current/static/tutorial-window.html) माता-पिता के चिल्ड्रन ऐरे में बच्चे की अनुक्रमणिका तैयार करता है।
डी:रिकर्सन भाग एक अंतर के साथ प्रारंभिक भाग के रूप में काम करता है:यह मूल तत्व की खोज नहीं कर रहा है बल्कि उस तत्व के लिए है जिसमें अंतिम रिकर्सन का मूल नोड है।
ई:बिना किसी बच्चे के सभी तत्वों को पुनरावर्तन और फ़िल्टर करना यह परिणाम देता है:
node_id path json
2 children,0 {"name": "node2", "children": []}
4 children,0,children,0 {"name": "node4", "children": []}
5 children,0,children,1 {"name": "node5", "children": []}
6 children,0,children,2 {"name": "node6", "children": []}
3 children,1 {"name": "node3", "children": []}
7 children,1,children,0 {"name": "node7", "children": []}
8 children,1,children,1 {"name": "node8", "children": []}
हालांकि मुझे रिकर्सन में सभी बच्चों के तत्वों को जोड़ने का कोई तरीका नहीं मिला (मूल जेसन कोई वैश्विक चर नहीं है; इसलिए यह हमेशा प्रत्यक्ष पूर्वजों के परिवर्तनों को जानता है, उनके भाई बहनों को नहीं), मुझे एक सेकंड चरण में पंक्तियों को फिर से शुरू करना पड़ा।पी>
इसलिए मैं फ़ंक्शन का निर्माण करता हूं। वहां मैं वैश्विक चर के लिए पुनरावृत्ति कर सकता हूं। फ़ंक्शन के साथ jsonb_insert
मैं सभी परिकलित तत्वों को एक रूट जोंस ऑब्जेक्ट में सम्मिलित कर रहा हूं - परिकलित पथ का उपयोग करके।
CREATE OR REPLACE FUNCTION json_tree() RETURNS jsonb AS $$
DECLARE
_json_output jsonb;
_temprow record;
BEGIN
SELECT
jsonb_build_object('name', name, 'children', array_to_json(ARRAY[]::int[]))
INTO _json_output
FROM test
WHERE parent_node IS NULL;
FOR _temprow IN
/* Query above */
LOOP
SELECT jsonb_insert(_json_output, _temprow.path, _temprow.json) INTO _json_output;
END LOOP;
RETURN _json_output;
END;
$$ LANGUAGE plpgsql;
अंतिम चरण फ़ंक्शन को कॉल करना और JSON को अधिक पठनीय बनाना है (jsonb_pretty()
)
{
"name": "node1",
"children": [{
"name": "node2",
"children": [{
"name": "node4",
"children": []
},
{
"name": "node5",
"children": []
},
{
"name": "node6",
"children": []
}]
},
{
"name": "node3",
"children": [{
"name": "node7",
"children": []
},
{
"name": "node8",
"children": []
}]
}]
}
मुझे यकीन है कि क्वेरी को अनुकूलित करना संभव है लेकिन एक स्केच के लिए यह काम करता है।