如何使用 PostgreSQL JSONB_SET() 创建新的深层对象元素
How to use PostgreSQL JSONB_SET() to create new deep object element
我一定是遗漏了什么...似乎 JSONB_SET()
没有正常工作,因为 advertised?
SELECT JSONB_SET(
'{"k1": {"value": "v1"}}',
'{k2,value}',
'"v2"',
TRUE
);
结果:
----+------------------------
| jsonb_set
| jsonb
----+------------------------
1 | {"k1": {"value": "v1"}}
----+------------------------
我期待 {"k1": {"value": "v1"}, "k2": {"value": "v2"}}
我还尝试将 FALSE
作为第四个参数,以防它被颠倒或发生其他情况。
我正在使用 PostgreSQL 9.6.4
文档说:
jsonb_set(target jsonb, path text[], new_value jsonb[, create_missing
boolean])
在您的示例中,第二个参数 - '{k2,value}'
是搜索路径,但由于第一个路径 k2
不存在,因此结果为 NULL before value
可能是 added/replaced.
简单来说 - jsonb_set 并不是要按照您尝试使用搜索路径的方式构建整个 JSON 文档,而是要添加或替换 单个 key/value.
如果你想要 add/replace 全新的一组 JSON,你可以使用 ||
(连接)运算符来代替:
-- Add example:
SELECT $${"k1": {"value": "v1"}}$$::jsonb || $${ "k2": { "value": "v2"}}$$::jsonb;
?column?
------------------------------------------------
{"k1": {"value": "v1"}, "k2": {"value": "v2"}}
(1 row)
-- Replace example
SELECT $${"k1": {"value": "v1"}}$$::jsonb || $${ "k1": { "value": "v2"}}$$::jsonb;
?column?
-------------------------
{"k1": {"value": "v2"}}
(1 row)
或
您可以这样使用 jsonb_set()
:
SELECT JSONB_SET(
'{"k1": {"value": "v1"}}',
'{k2}',
'{"value": "v2"}',
TRUE
);
jsonb_set
------------------------------------------------
{"k1": {"value": "v1"}, "k2": {"value": "v2"}}
(1 row)
我刚遇到同样的问题并为此创建了一个简单的 postgres-function。
它可能不是最快的解决方案并且对于深度插入可能特别慢,但到目前为止对我来说效果很好!
CREATE OR REPLACE FUNCTION jsonb_deep_set(curjson jsonb, globalpath text[], newval jsonb) RETURNS jsonb AS
$$
BEGIN
IF curjson is null THEN
curjson := '{}'::jsonb;
END IF;
FOR index IN 1..ARRAY_LENGTH(globalpath, 1) LOOP
IF curjson #> globalpath[1:index] is null THEN
curjson := jsonb_set(curjson, globalpath[1:index], '{}');
END IF;
END LOOP;
curjson := jsonb_set(curjson, globalpath, newval);
RETURN curjson;
END;
$$
LANGUAGE 'plpgsql';
将 jsonb
替换为 json
使其也适用于 json 个对象。
为了实现深层嵌套字段的“安全值设置”(无需在数据库中创建新的 PostgreSQL 函数),我使用以下模式:(作为第一个 mentioned here)
update "myTable" set "myField" =
jsonb_set(COALESCE("myField", '{}'), '{"depth1"}',
jsonb_set(COALESCE("myField"->'depth1', '{}'), '{"depth2"}',
jsonb_set(COALESCE("myField"->'depth1'->'depth2', '{}'), '{"depth3"}',
jsonb_set(COALESCE("myField"->'depth1'->'depth2'->'depth3', '{}'), '{"depth4"}',
'"newValue"'
)))) where "id" = 'myRowID' returning *
对于那些可能不喜欢上述调用的深层嵌套性质的人,这里有一个替代方案:
update "myTable" set "myField" = jsonb_set(
CASE
WHEN "myField" IS NULL THEN '{"depth1": {"depth2": {"depth3": {}}}}'
WHEN "myField"->'depth1' IS NULL THEN jsonb_set("myField", array['depth1'], '{"depth2": {"depth3": {}}}')
WHEN "myField"->'depth1'->'depth2' IS NULL THEN jsonb_set("myField", array['depth1','depth2'], '{"depth3": {}}')
WHEN "myField"->'depth1'->'depth2'->'depth3' IS NULL THEN jsonb_set("myField", array['depth1','depth2','depth3'], '{}')
ELSE "myField"
END,
array['depth1','depth2','depth3','depth4'],
'"newValue"'
) where "id" = 'myRowID' returning *
我一定是遗漏了什么...似乎 JSONB_SET()
没有正常工作,因为 advertised?
SELECT JSONB_SET(
'{"k1": {"value": "v1"}}',
'{k2,value}',
'"v2"',
TRUE
);
结果:
----+------------------------
| jsonb_set
| jsonb
----+------------------------
1 | {"k1": {"value": "v1"}}
----+------------------------
我期待 {"k1": {"value": "v1"}, "k2": {"value": "v2"}}
我还尝试将 FALSE
作为第四个参数,以防它被颠倒或发生其他情况。
我正在使用 PostgreSQL 9.6.4
文档说:
jsonb_set(target jsonb, path text[], new_value jsonb[, create_missing boolean])
在您的示例中,第二个参数 - '{k2,value}'
是搜索路径,但由于第一个路径 k2
不存在,因此结果为 NULL before value
可能是 added/replaced.
简单来说 - jsonb_set 并不是要按照您尝试使用搜索路径的方式构建整个 JSON 文档,而是要添加或替换 单个 key/value.
如果你想要 add/replace 全新的一组 JSON,你可以使用 ||
(连接)运算符来代替:
-- Add example:
SELECT $${"k1": {"value": "v1"}}$$::jsonb || $${ "k2": { "value": "v2"}}$$::jsonb;
?column?
------------------------------------------------
{"k1": {"value": "v1"}, "k2": {"value": "v2"}}
(1 row)
-- Replace example
SELECT $${"k1": {"value": "v1"}}$$::jsonb || $${ "k1": { "value": "v2"}}$$::jsonb;
?column?
-------------------------
{"k1": {"value": "v2"}}
(1 row)
或
您可以这样使用 jsonb_set()
:
SELECT JSONB_SET(
'{"k1": {"value": "v1"}}',
'{k2}',
'{"value": "v2"}',
TRUE
);
jsonb_set
------------------------------------------------
{"k1": {"value": "v1"}, "k2": {"value": "v2"}}
(1 row)
我刚遇到同样的问题并为此创建了一个简单的 postgres-function。 它可能不是最快的解决方案并且对于深度插入可能特别慢,但到目前为止对我来说效果很好!
CREATE OR REPLACE FUNCTION jsonb_deep_set(curjson jsonb, globalpath text[], newval jsonb) RETURNS jsonb AS
$$
BEGIN
IF curjson is null THEN
curjson := '{}'::jsonb;
END IF;
FOR index IN 1..ARRAY_LENGTH(globalpath, 1) LOOP
IF curjson #> globalpath[1:index] is null THEN
curjson := jsonb_set(curjson, globalpath[1:index], '{}');
END IF;
END LOOP;
curjson := jsonb_set(curjson, globalpath, newval);
RETURN curjson;
END;
$$
LANGUAGE 'plpgsql';
将 jsonb
替换为 json
使其也适用于 json 个对象。
为了实现深层嵌套字段的“安全值设置”(无需在数据库中创建新的 PostgreSQL 函数),我使用以下模式:(作为第一个 mentioned here)
update "myTable" set "myField" =
jsonb_set(COALESCE("myField", '{}'), '{"depth1"}',
jsonb_set(COALESCE("myField"->'depth1', '{}'), '{"depth2"}',
jsonb_set(COALESCE("myField"->'depth1'->'depth2', '{}'), '{"depth3"}',
jsonb_set(COALESCE("myField"->'depth1'->'depth2'->'depth3', '{}'), '{"depth4"}',
'"newValue"'
)))) where "id" = 'myRowID' returning *
对于那些可能不喜欢上述调用的深层嵌套性质的人,这里有一个替代方案:
update "myTable" set "myField" = jsonb_set(
CASE
WHEN "myField" IS NULL THEN '{"depth1": {"depth2": {"depth3": {}}}}'
WHEN "myField"->'depth1' IS NULL THEN jsonb_set("myField", array['depth1'], '{"depth2": {"depth3": {}}}')
WHEN "myField"->'depth1'->'depth2' IS NULL THEN jsonb_set("myField", array['depth1','depth2'], '{"depth3": {}}')
WHEN "myField"->'depth1'->'depth2'->'depth3' IS NULL THEN jsonb_set("myField", array['depth1','depth2','depth3'], '{}')
ELSE "myField"
END,
array['depth1','depth2','depth3','depth4'],
'"newValue"'
) where "id" = 'myRowID' returning *