使用 jsonb_set() 更新特定的 jsonb 数组值
Using jsonb_set() for updating specific jsonb array value
目前我正在使用 PostgreSQL 9.5 并尝试更新 jsonb 字段数组中的值。但是我无法获取所选值的索引
我的 table 看起来像这样:
CREATE TABLE samples (
id serial,
sample jsonb
);
我的 JSON 看起来像这样:
{"result": [
{"8410": "ABNDAT", "8411": "Abnahmedatum"},
{"8410": "ABNZIT", "8411": "Abnahmezeit"},
{"8410": "FERR_R", "8411": "Ferritin"}
]}
我的 SELECT 获取正确值的语句有效:
SELECT
id, value
FROM
samples s, jsonb_array_elements(s.sample#>'{result}') r
WHERE
s.id = 26 and r->>'8410' = 'FERR_R';
结果:
id | value
----------------------------------------------
26 | {"8410": "FERR_R", "8411": "Ferritin"}
好的,这就是我想要的。现在我想使用以下 UPDATE 语句执行更新以添加新元素“ratingtext”(如果还没有的话):
UPDATE
samples s
SET
sample = jsonb_set(sample,
'{result,2,ratingtext}',
'"Some individual text"'::jsonb,
true)
WHERE
s.id = 26;
执行UPDATE语句后,我的数据是这样的(也是正确的):
{"result": [
{"8410": "ABNDAT", "8411": "Abnahmedatum"},
{"8410": "ABNZIT", "8411": "Abnahmezeit"},
{"8410": "FERR_R", "8411": "Ferritin", "ratingtext": "Some individual text"}
]}
到目前为止一切顺利,但我手动 搜索了索引值 2 以获取 JSON 数组中的正确元素。如果要更改顺序,这将不起作用。
所以我的问题是:
有没有办法获取选中的JSON数组元素的索引,并将SELECT语句和UPDATE语句合二为一?
就像:
UPDATE
samples s
SET
sample = jsonb_set(sample,
'{result,' || INDEX OF ELEMENT || ',ratingtext}',
'"Some individual text"'::jsonb,
true)
WHERE
s.id = 26;
samples.id 和 "8410" 的值在准备语句之前已知。
或者目前无法做到这一点?
您可以使用jsonb_array_elements() with ordinality
找到搜索元素的索引(注意,ordinality
从1开始,而json数组的第一个索引是0):
select
pos- 1 as elem_index
from
samples,
jsonb_array_elements(sample->'result') with ordinality arr(elem, pos)
where
id = 26 and
elem->>'8410' = 'FERR_R';
elem_index
------------
2
(1 row)
使用上面的查询根据索引更新元素(注意 jsonb_set()
的第二个参数是一个文本数组):
update
samples
set
sample =
jsonb_set(
sample,
array['result', elem_index::text, 'ratingtext'],
'"some individual text"'::jsonb,
true)
from (
select
pos- 1 as elem_index
from
samples,
jsonb_array_elements(sample->'result') with ordinality arr(elem, pos)
where
id = 26 and
elem->>'8410' = 'FERR_R'
) sub
where
id = 26;
结果:
select id, jsonb_pretty(sample)
from samples;
id | jsonb_pretty
----+--------------------------------------------------
26 | { +
| "result": [ +
| { +
| "8410": "ABNDAT", +
| "8411": "Abnahmedatum" +
| }, +
| { +
| "8410": "ABNZIT", +
| "8411": "Abnahmezeit" +
| }, +
| { +
| "8410": "FERR_R", +
| "8411": "Ferritin", +
| "ratingtext": "Some individual text"+
| } +
| ] +
| }
(1 row)
jsonb_set()
中的最后一个参数应该是 true
,以便在其键尚不存在时强制添加新值。但是可以跳过它,因为它的默认值为 true
.
虽然并发问题似乎不太可能(由于限制性 WHERE 条件和受影响的行数可能很少),您可能也对 Atomic UPDATE .. SELECT in Postgres.
感兴趣
目前我正在使用 PostgreSQL 9.5 并尝试更新 jsonb 字段数组中的值。但是我无法获取所选值的索引
我的 table 看起来像这样:
CREATE TABLE samples (
id serial,
sample jsonb
);
我的 JSON 看起来像这样:
{"result": [
{"8410": "ABNDAT", "8411": "Abnahmedatum"},
{"8410": "ABNZIT", "8411": "Abnahmezeit"},
{"8410": "FERR_R", "8411": "Ferritin"}
]}
我的 SELECT 获取正确值的语句有效:
SELECT
id, value
FROM
samples s, jsonb_array_elements(s.sample#>'{result}') r
WHERE
s.id = 26 and r->>'8410' = 'FERR_R';
结果:
id | value
----------------------------------------------
26 | {"8410": "FERR_R", "8411": "Ferritin"}
好的,这就是我想要的。现在我想使用以下 UPDATE 语句执行更新以添加新元素“ratingtext”(如果还没有的话):
UPDATE
samples s
SET
sample = jsonb_set(sample,
'{result,2,ratingtext}',
'"Some individual text"'::jsonb,
true)
WHERE
s.id = 26;
执行UPDATE语句后,我的数据是这样的(也是正确的):
{"result": [
{"8410": "ABNDAT", "8411": "Abnahmedatum"},
{"8410": "ABNZIT", "8411": "Abnahmezeit"},
{"8410": "FERR_R", "8411": "Ferritin", "ratingtext": "Some individual text"}
]}
到目前为止一切顺利,但我手动 搜索了索引值 2 以获取 JSON 数组中的正确元素。如果要更改顺序,这将不起作用。
所以我的问题是:
有没有办法获取选中的JSON数组元素的索引,并将SELECT语句和UPDATE语句合二为一?
就像:
UPDATE
samples s
SET
sample = jsonb_set(sample,
'{result,' || INDEX OF ELEMENT || ',ratingtext}',
'"Some individual text"'::jsonb,
true)
WHERE
s.id = 26;
samples.id 和 "8410" 的值在准备语句之前已知。
或者目前无法做到这一点?
您可以使用jsonb_array_elements() with ordinality
找到搜索元素的索引(注意,ordinality
从1开始,而json数组的第一个索引是0):
select
pos- 1 as elem_index
from
samples,
jsonb_array_elements(sample->'result') with ordinality arr(elem, pos)
where
id = 26 and
elem->>'8410' = 'FERR_R';
elem_index
------------
2
(1 row)
使用上面的查询根据索引更新元素(注意 jsonb_set()
的第二个参数是一个文本数组):
update
samples
set
sample =
jsonb_set(
sample,
array['result', elem_index::text, 'ratingtext'],
'"some individual text"'::jsonb,
true)
from (
select
pos- 1 as elem_index
from
samples,
jsonb_array_elements(sample->'result') with ordinality arr(elem, pos)
where
id = 26 and
elem->>'8410' = 'FERR_R'
) sub
where
id = 26;
结果:
select id, jsonb_pretty(sample)
from samples;
id | jsonb_pretty
----+--------------------------------------------------
26 | { +
| "result": [ +
| { +
| "8410": "ABNDAT", +
| "8411": "Abnahmedatum" +
| }, +
| { +
| "8410": "ABNZIT", +
| "8411": "Abnahmezeit" +
| }, +
| { +
| "8410": "FERR_R", +
| "8411": "Ferritin", +
| "ratingtext": "Some individual text"+
| } +
| ] +
| }
(1 row)
jsonb_set()
中的最后一个参数应该是 true
,以便在其键尚不存在时强制添加新值。但是可以跳过它,因为它的默认值为 true
.
虽然并发问题似乎不太可能(由于限制性 WHERE 条件和受影响的行数可能很少),您可能也对 Atomic UPDATE .. SELECT in Postgres.
感兴趣