我在数据库(postgres 9.2.1)中有一个文本字段,其中有一个 json blob。它看起来与此类似,除了所有内容都在一行上,显然:
{
"keyword": {
"checked": "1",
"label": "Keyword"
},
"agency_name": {
"checked": "0",
"label": "Agency Name"
}
}
我需要向 json 数组添加一个元素,使其看起来像这样:
{
"keyword": {
"checked": "1",
"label": "Keyword"
},
"something_new": {
"checked": "1",
"label": "Something New"
},
"agency_name": {
"checked": "0",
"label": "Agency Name"
}
}
我不太关心新数组元素的放置。它可能位于 Agency_name 之后。在 postgres 中有一个简单的方法可以做到这一点吗?
如果升级到PG9.5.1,那么可以使用sql操作符
||
来合并jsonb,例子
select '{"a":1}'::jsonb || '{"a":2, "b":2}'::jsonb
会回来
{"a": 2, "b": 2}
如果您无法升级到 pg9.5.1,恕我直言,在您的代码中完成这项工作将是更好的选择。您可以将旧的 jsonb 字符串解析为映射,然后更新映射,然后转换为字符串并更新 db-record。
如果我们想要更新(添加)一个 JSONB 字段:
UPDATE <table>
SET <field-name> = <field-name> || '{"a": 1}'::jsonb
WHERE id = <some id>
使用
||
合并jsonb并为其设置值
示例:
产地:
表中
a
:
id |信息
1 | {“aa”:“bb”}
2 | {“aa”:“cc”}
执行后:
update a set info = info::jsonb || ('{"id":' || id || '}' )::jsonb
生成:
id |信息
1 | {"aa":"bb","id":1}
2 | {"aa":"cc","id":2}
别的东西:
-
‘key’
删除 jsonb 中的元素即使我遇到了同样的问题,我想动态地将新元素附加到 jsonb[]。
假设column_jsonb[] = [{"name":"xyz","age":"12"}]
UPDATE table_name
SET column_jsonb[] = array_append(column_jsonb[],'{"name":"abc","age":"22"}');
结果:[{"姓名":"xyz","年龄":"12"},{"姓名":"abc","年龄":"22"}]
PostgreSQL 还没有太多 JSON 支持函数:我能看到的只是像
array_to_json
这样的函数,如果有相应的方法将原始 JSON 转换为数组,然后您可以对其进行操作,这可能会很有用在转换回 JSON 之前添加该附加元素。
可能最好的办法是使用 PL 语言来操作 JSON。 其中一个明显的例子是 PLV8,它在 PostgreSQL 中提供 JavaScript 编程功能。 您可以在 JavaScript 中编写一个用户定义的函数,该函数将相应地操作 JSON blob:
当然,许多其他 PL 语言(例如 Java、Python 或 Perl)可能同样擅长处理 JSON 数据,并且可能更容易安装在您的系统上。 如果您设置了用户定义的函数,则可以在其中每个函数中编写用户定义的函数。
版本 9.5 提供了 jsonb_set 函数,create_missing=TRUE。 在任何其他情况下,请使用以下技巧来附加信息:
SELECT (trim( trailing '}' from data::text) || ', "c":2}')::json
使用更正确的方式添加/替换新值:
UPDATE t
SET data=t3.data
FROM t AS t1
INNER JOIN
(
SELECT id, json_object_agg(t.k,t.v)
FROM
(
SELECT *
FROM (SELECT id, json_object_keys(data) as k, data->json_object_keys(data) as v FROM t) as t2
WHERE t.k != 'c'
UNION ALL
SELECT id, 'c'::text as k, '"new value"'::json as v FROM t1
) as t3
GROUP by id
) as t4 ON (t1.id=t4.id)
删除钥匙:
UPDATE t
SET data=t3.data
FROM t AS t1
INNER JOIN
(
SELECT id, json_object_agg(t.k,t.v)
FROM (SELECT id, json_object_keys(data) as k, data->json_object_keys(data) as v FROM t) as t2
WHERE t.k != 'c'
GROUP by id
) as t4 ON (t1.id=t4.id)
我也遇到过这个问题。 这个解决方案是相当“纯粹”的对象操作,我更喜欢“sql”函数而不是 plpgsql。 主要的事情是使用 json_each 进行分解 - 给你一条记录 - 然后从
创建一条记录CREATE OR REPLACE FUNCTION json_extend_object(
input_object json,
append_key text,
append_object json)
RETURNS json AS
$BODY$
select json_object_agg (((json_val)::record).key, ((json_val)::record).value)
from (
select json_val
from (select json_each (input_object) as json_val) disaggr
where ((json_val::record).key != append_key)
union
select newvals
from (
select append_key, append_object
) newvals
) to_rows;
$BODY$
LANGUAGE sql IMMUTABLE
;
Andrew Wolfe 提供的解决方案很好,但与 postgres 版本不兼容< 9.4. And if you have a 9.4+ version, just use jsonb and || (concatenate) operator to add an element to json.
所以,这是 json_extend_object 的 9.3 兼容版本:
CREATE OR REPLACE FUNCTION json_extend_object(
input_object json,
append_key text,
append_object json)
RETURNS json AS
$BODY$
select ('{'||string_agg(''||to_json((json_val::record).key)||':'|| to_json((json_val::record).value), ',')||'}')::json
from (
select json_val
from (select json_each (input_object) as json_val) jsonvals
where ((json_val::record).key != append_key)
union
select newvals
from (select append_key, append_object) newvals
) to_rows;
$BODY$
LANGUAGE sql IMMUTABLE;