gpt4 book ai didi

json - postgresql - 查询以建立 json

转载 作者:行者123 更新时间:2023-11-29 11:44:40 24 4
gpt4 key购买 nike

运行:PostgreSQL 9.6.2

我将数据以键/值对的形式存储在表中。 “key”其实就是一个json对象的路径,每一个都是一个属性。因此,例如,如果键是“cogs”、“props1”、“value”,则 json 对象将如下所示:

{
"cogs":{
"props1": {
"value": 100
}
}
}

如果可能的话,我想通过 SQL 查询以某种方式重建一个 json 对象。这是测试数据集:

drop table if exists test_table;
CREATE TABLE test_table
(
id serial,
file_id integer NOT NULL,
key character varying[],
value character varying,
status character varying
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;

insert into test_table (file_id, key, value, status)
values (1, '{"cogs","description"}', 'some awesome cog', 'approved');
insert into test_table (file_id, key, value, status)
values (1, '{"cogs","display"}', 'Giant Cog', null);
insert into test_table (file_id, key, value, status)
values (1, '{"cogs","props1","value"}', '100', 'not verified');
insert into test_table (file_id, key, value, status)
values (1, '{"cogs","props1","id"}', 26, 'approved');
insert into test_table (file_id, key, value, status)
values (1, '{"cogs","props1","dimensions"}', '{"200", "300"}', null);
insert into test_table (file_id, key, value, status)
values (1, '{"cogs","props2","value"}', '200', 'not verified');
insert into test_table (file_id, key, value, status)
values (1, '{"cogs","props2","id"}', 27, 'approved');
insert into test_table (file_id, key, value, status)
values (1, '{"cogs","props2","dimensions"}', '{"700", "800"}', null);

insert into test_table (file_id, key, value, status)
values (1, '{"widgets","description"}', 'some awesome widget', 'approved');
insert into test_table (file_id, key, value, status)
values (1, '{"widgets","display"}', 'Giant Widget', null);
insert into test_table (file_id, key, value, status)
values (1, '{"widgets","props1","value"}', '100', 'not verified');
insert into test_table (file_id, key, value, status)
values (1, '{"widgets","props1","id"}', 28, 'approved');
insert into test_table (file_id, key, value, status)
values (1, '{"widgets","props1","dimensions"}', '{"200", "300"}', null);
insert into test_table (file_id, key, value, status)
values (1, '{"widgets","props2","value"}', '200', 'not verified');
insert into test_table (file_id, key, value, status)
values (1, '{"widgets","props2","id"}', 29, 'approved');
insert into test_table (file_id, key, value, status)
values (1, '{"widgets","props2","dimensions"}', '{"900", "1000"}', null);

我正在寻找的输出是这种格式:

{
"cogs": {
"description": "some awesome cog",
"display": "Giant Cog",
"props1": {
"value": 100,
"id": 26,
"dimensions": [200, 300]
},
"props2": {
"value": 200,
"id": 27,
"dimensions": [700, 800]
}
},
"widgets": {
"description": "some awesome widget",
"display": "Giant Widget",
"props1": {
"value": 100,
"id": 28,
"dimensions": [200, 300]
},
"props2": {
"value": 200,
"id": 29,
"dimensions": [900, 1000]
}
}
}

我面临的一些问题:

  1. “值”列可以包含文本、数字和数组。无论出于何种原因,使用 knex.js 的服务器端代码将整数数组(即 [100,300])存储到 postgres 中,格式如下:{"100","300"}。我需要确保我也将其提取为整数数组。

  2. 努力使这种动态成为可能。也许是一个递归过程来找出“关键”路径的深度……而不是硬编码数组查找值。

  3. json_object_agg 可以很好地将属性分组到单个对象中。但是,当遇到空值时它会中断。因此,如果“key”列只有两个值(即“cogs”、“description”),我尝试聚合一个长度为三的数组(即“cogs”、“props1”、“value”),除非我只过滤长度为 3 的数组,否则它将中断。

  4. 保留输入的顺序。下面的 @klin 解决方案很棒,让我完成了 95% 的工作。但是我没有提到还要保留顺序...

最佳答案

动态解决方案需要一些工作。

首先,我们需要一个函数来将文本数组和值转换为 jsonb 对象。

create or replace function keys_to_object(keys text[], val text)
returns jsonb language plpgsql as $$
declare
i int;
rslt jsonb = to_jsonb(val);
begin
for i in select generate_subscripts(keys, 1, true) loop
rslt := jsonb_build_object(keys[i], rslt);
end loop;
return rslt;
end $$;

select keys_to_object(array['key', 'subkey', 'subsub'], 'value');

keys_to_object
------------------------------------------
{"key": {"subkey": {"subsub": "value"}}}
(1 row)

接下来,另一个合并 jsonb 对象的函数(参见 Merging JSONB values in PostgreSQL)。

create or replace function jsonb_merge(a jsonb, b jsonb) 
returns jsonb language sql as $$
select
jsonb_object_agg(
coalesce(ka, kb),
case
when va isnull then vb
when vb isnull then va
when jsonb_typeof(va) <> 'object' or jsonb_typeof(vb) <> 'object' then vb
else jsonb_merge(va, vb) end
)
from jsonb_each(a) e1(ka, va)
full join jsonb_each(b) e2(kb, vb) on ka = kb
$$;

select jsonb_merge('{"key": {"subkey1": "value1"}}', '{"key": {"subkey2": "value2"}}');

jsonb_merge
-----------------------------------------------------
{"key": {"subkey1": "value1", "subkey2": "value2"}}
(1 row)

最后,让我们根据上面的函数创建一个聚合,

create aggregate jsonb_merge_agg(jsonb)
(
sfunc = jsonb_merge,
stype = jsonb
);

我们完成了:

select jsonb_pretty(jsonb_merge_agg(keys_to_object(key, translate(value, '{}"', '[]'))))
from test_table;

jsonb_pretty
----------------------------------------------
{ +
"cogs": { +
"props1": { +
"id": "26", +
"value": "100", +
"dimensions": "[200, 300]" +
}, +
"props2": { +
"id": "27", +
"value": "200", +
"dimensions": "[700, 800]" +
}, +
"display": "Giant Cog", +
"description": "some awesome cog" +
}, +
"widgets": { +
"props1": { +
"id": "28", +
"value": "100", +
"dimensions": "[200, 300]" +
}, +
"props2": { +
"id": "29", +
"value": "200", +
"dimensions": "[900, 1000]" +
}, +
"display": "Giant Widget", +
"description": "some awesome widget"+
} +
}
(1 row)

关于json - postgresql - 查询以建立 json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44141483/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com