Mac*_*rio 10 postgresql json adjacency-list
我对tags表有以下架构:
CREATE TABLE tags (
id integer NOT NULL,
name character varying(255) NOT NULL,
parent_id integer
);
Run Code Online (Sandbox Code Playgroud)
我需要构建一个查询来返回以下结构(为了便于阅读,这里表示为yaml):
- name: Ciencia
parent_id:
id: 7
children:
- name: Química
parent_id: 7
id: 9
children: []
- name: Biología
parent_id: 7
id: 8
children:
- name: Botánica
parent_id: 8
id: 19
children: []
- name: Etología
parent_id: 8
id: 18
children: []
Run Code Online (Sandbox Code Playgroud)
经过一些试验和错误,并在SO中寻找类似的问题,我想出了这个问题:
WITH RECURSIVE tagtree AS (
SELECT tags.name, tags.parent_id, tags.id, json '[]' children
FROM tags
WHERE NOT EXISTS (SELECT 1 FROM tags tt WHERE tt.parent_id = tags.id)
UNION ALL
SELECT (tags).name, (tags).parent_id, (tags).id, array_to_json(array_agg(tagtree)) children FROM (
SELECT tags, tagtree
FROM tagtree
JOIN tags ON tagtree.parent_id = tags.id
) v
GROUP BY v.tags
)
SELECT array_to_json(array_agg(tagtree)) json
FROM tagtree
WHERE parent_id IS NULL
Run Code Online (Sandbox Code Playgroud)
但是转换为yaml时会返回以下结果:
- name: Ciencia
parent_id:
id: 7
children:
- name: Química
parent_id: 7
id: 9
children: []
- name: Ciencia
parent_id:
id: 7
children:
- name: Biología
parent_id: 7
id: 8
children:
- name: Botánica
parent_id: 8
id: 19
children: []
- name: Etología
parent_id: 8
id: 18
children: []
Run Code Online (Sandbox Code Playgroud)
根节点是重复的.我可以将结果合并到我的应用程序代码中的预期结果,但我觉得我很接近,它可以从PG完成.
以下是SQL Fiddle的一个示例:http://sqlfiddle.com/#!15/1846e/1/0
这是使用PLV8为您的架构的解决方案.
首先,使用PLSQL函数和递归CTE构建物化路径.
CREATE OR REPLACE FUNCTION get_children(tag_id integer)
RETURNS json AS $$
DECLARE
result json;
BEGIN
SELECT array_to_json(array_agg(row_to_json(t))) INTO result
FROM (
WITH RECURSIVE tree AS (
SELECT id, name, ARRAY[]::INTEGER[] AS ancestors
FROM tags WHERE parent_id IS NULL
UNION ALL
SELECT tags.id, tags.name, tree.ancestors || tags.parent_id
FROM tags, tree
WHERE tags.parent_id = tree.id
) SELECT id, name, ARRAY[]::INTEGER[] AS children FROM tree WHERE $1 = tree.ancestors[array_upper(tree.ancestors,1)]
) t;
RETURN result;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
然后,从上面函数的输出构建树.
CREATE OR REPLACE FUNCTION get_tree(data json) RETURNS json AS $$
var root = [];
for(var i in data) {
build_tree(data[i]['id'], data[i]['name'], data[i]['children']);
}
function build_tree(id, name, children) {
var exists = getObject(root, id);
if(exists) {
exists['children'] = children;
}
else {
root.push({'id': id, 'name': name, 'children': children});
}
}
function getObject(theObject, id) {
var result = null;
if(theObject instanceof Array) {
for(var i = 0; i < theObject.length; i++) {
result = getObject(theObject[i], id);
if (result) {
break;
}
}
}
else
{
for(var prop in theObject) {
if(prop == 'id') {
if(theObject[prop] === id) {
return theObject;
}
}
if(theObject[prop] instanceof Object || theObject[prop] instanceof Array) {
result = getObject(theObject[prop], id);
if (result) {
break;
}
}
}
}
return result;
}
return JSON.stringify(root);
$$ LANGUAGE plv8 IMMUTABLE STRICT;
Run Code Online (Sandbox Code Playgroud)
这将产生您问题中提到的所需JSON.希望有所帮助.
我写的这个解决方案是如何工作的具体岗位/击穿这里.