Sql 如何根据Postgres中的筛选条件更新深度嵌套的JSON对象?
我有一个表Sql 如何根据Postgres中的筛选条件更新深度嵌套的JSON对象?,sql,json,postgresql,postgresql-9.5,Sql,Json,Postgresql,Postgresql 9.5,我有一个表mapping\u transform,其中有一个JSONB列content\u json包含如下内容 { "meta": {...}, "mapping": [ ..., { "src": "up", "dest": "down", ... }, ... ] } WITH elems AS (SELECT json_arra
mapping\u transform
,其中有一个JSONB列content\u json
包含如下内容
{
"meta": {...},
"mapping": [
...,
{
"src": "up",
"dest": "down",
...
},
...
]
}
WITH elems AS (SELECT json_array_elements(content_json->'mapping') from mapping_transform),
results SELECT * FROM elems WHERE json_array_elements->>'src' = 'up' and json_array_elements->>'dest' = 'down'
UPDATE mapping_transform
SET content_json = jsonb_set(results, '{"rule_names"}', '["some name"]'); -- this does obviously not work
我想在JSON对象中添加一个新的JSON条目(“rule_names”):[“some name”]
)来匹配src
=up
和dest
=down
,这将导致
{
"meta": {...},
"mapping": [
...,
{
"src": "up",
"dest": "down",
...,
"rule_names": [ "some name" ]
},
...
]
}
以下查询返回满足筛选要求的JSON对象:
WITH elems AS (SELECT json_array_elements(content_json->'mapping') from mapping_transform)
SELECT * FROM elems WHERE json_array_elements->>'src' = 'up' and json_array_elements->>'dest' = 'down';
-- Alternative
SELECT mt_entry
FROM mapping_transform,
LATERAL jsonb_array_elements(content_json::jsonb->'mapping') mt_entry
WHERE mt_entry->>'src' = 'up' and mt_entry->>'dest' = 'down';
我现在的问题是,我不知道如何将新条目添加到特定对象。我试过类似的东西
{
"meta": {...},
"mapping": [
...,
{
"src": "up",
"dest": "down",
...
},
...
]
}
WITH elems AS (SELECT json_array_elements(content_json->'mapping') from mapping_transform),
results SELECT * FROM elems WHERE json_array_elements->>'src' = 'up' and json_array_elements->>'dest' = 'down'
UPDATE mapping_transform
SET content_json = jsonb_set(results, '{"rule_names"}', '["some name"]'); -- this does obviously not work
但这不会执行,因为结果
是未知列。在分配给content\u json
之前,我确实需要将jsonb\u集的结果与content\u json
的其余部分合并,因为否则它将覆盖整个内容
如何根据筛选条件更新特定的深度嵌套JSON对象?
如果我有一个定义良好的路径来确定我要更新的对象的位置,事情就会容易得多。但是,由于目标对象位于JSON数组中并且具有任意位置,查找和更新它要困难得多。请注意,我加入text=text(因为我不知道你的主键是什么-不推荐)。左侧为要更新的值,右侧为原始值:
vao=# with num as (select content_json,val,ord from mapping_transform, json_array_elements(content_json->'mapping') with ordinality as o (val,ord) where val->>'src' = 'up')
select
jsonb_pretty(
jsonb_set(t.content_json::jsonb,concat('{mapping,',(ord::int-1),'}')::text[],((t.content_json->'mapping'->(ord::int-1))::jsonb||'{"rule_names":["some name"]}')::jsonb)
)
, jsonb_pretty(t.content_json::jsonb)
from mapping_transform t
join num on num.content_json::text = t.content_json::text
/* of course join should be on PK, not text representation*/
;
jsonb_pretty | jsonb_pretty
-----------------------------+----------------------------
{ +| { +
"meta": { +| "meta": { +
"a": true +| "a": true +
}, +| }, +
"mapping": [ +| "mapping": [ +
"a", +| "a", +
"c", +| "c", +
{ +| { +
"a": 0, +| "a": 0, +
"src": "up", +| "src": "up", +
"dest": "down",+| "dest": "down"+
"rule_names": [+| }, +
"some name"+| "b" +
] +| ] +
}, +| }
"b" +|
] +|
} |
{ +| { +
"meta": { +| "meta": { +
"a": true +| "a": true +
}, +| }, +
"mapping": [ +| "mapping": [ +
"a", +| "a", +
{ +| { +
"a": 0, +| "a": 0, +
"src": "up", +| "src": "up", +
"dest": "down",+| "dest": "down"+
"rule_names": [+| }, +
"some name"+| "b" +
] +| ] +
}, +| }
"b" +|
] +|
} |
(2 rows)
建造:
vao=# create table mapping_transform(content_json jsonb);
CREATE TABLE
vao=# insert into mapping_transform select '{
"meta": {
"a": true
},
"mapping": ["a",{
"src": "up",
"dest": "down",
"a": 0
},
"b"
]
}';
INSERT 0 1
vao=# insert into mapping_transform select '{
"meta": {
"a": true
},
"mapping": ["a","c",{
"src": "up",
"dest": "down",
"a": 0
},
"b"
]
}';
INSERT 0 1
如果您熟悉JavaScript,您将乐于安装并使用此扩展,它允许您以本机方式修改json值,例如:
create extension if not exists plv8;
create or replace function update_mapping_v8(data json)
returns json language plv8 as $$
var len = data['mapping'].length;
for (var i = 0; i < len; i++) {
var o = data['mapping'][i];
if (o.src == 'up' && o.dest == 'down') {
o.rule_names = 'some name'
}
}
return data;
$$;
update mapping_transform
set content_json = update_mapping_v8(content_json);
问题是,假设目标对象位于数组中的位置0(content\u json->“mapping”->0
),但对象可以位于任何位置,请参见我问题的最后一句。这就是为什么我需要某种过滤,不能“通过路径到达对象”。啊。有时间我去看看later@TorstenScholz动态更新了生成路径的答案