以 JSONB 格式更新对象数组 PostgreSQL
Update array of objects in JSONB format PostgreSQL
我需要执行两个更新操作:
- 在第一种情况下更新将数据从字符串更改为布尔值
- 根据其他标签使用新名称和数据重新创建标签
jsonb 列中的示例数据:
[
{ "tax": "yes", "tax_percent": 20, "used_when": "after" },
{ "tax": "no", "tax_percent": 20 },
{ "tax_percent": 20, "used_when": "before" }
]
现在:
“税”值需要从是更新 -> 真,否或空(不存在)意味着 -> 假
"used_when" 需要更新为 "using" 并且如果之后 -> true,如果之前 OR null(不存在)意味着 -> false
所以它看起来像:
[
{ "tax": true, "tax_percent": 20, "using": true },
{ "tax": false, "tax_percent": 20, "using": false },
{ "tax": false, "tax_percent": 20, "using": false }
]
这些值是可选的,因此并非所有条目都有它,而且这是数据库列中的单行,因此需要为每一行更新列中的数据。
UPDATE t -- 5
SET mydata = s.new_data
FROM (
SELECT
id,
json_agg((using_updated - 'used_when')::json) as new_data -- 4
FROM t,
json_array_elements(t.mydata) as elements, -- 1
jsonb_set(elements::jsonb, '{tax}', -- 2
CASE
WHEN elements ->> 'tax' = 'yes' THEN 'true'::jsonb
ELSE 'false'::jsonb
END
) as tax_updated,
jsonb_set(tax_updated::jsonb, '{using}', -- 3
CASE
WHEN tax_updated ->> 'used_when' = 'true' THEN 'true'::jsonb
ELSE 'false'::jsonb
END
) as using_updated
GROUP BY id
) s
WHERE s.id = t.id;
- 将所有数组元素提取为每条记录一个元素
2/3。现在您可以使用
jsonb_set()
在数组元素中插入新的或更新现有的属性。 CASE
子句进行条件检查
- 消除剩余的
used_when
个元素。之后,您可以使用 json_agg 重新聚合更新的元素
- 做
UPDATE
如果您的数据类型为 json,您必须将类型转换为 jsonb,因为没有 json_set()
。如果没有,你当然可以忽略强制转换。
然而,正如@a_horse_with_no_name 正确提到的那样:您应该考虑不要将这些数据存储为纯 JSON 而是将它们提取到规范化的相对数据库 table 结构中,这使得事情更容易和更高效。
我需要执行两个更新操作:
- 在第一种情况下更新将数据从字符串更改为布尔值
- 根据其他标签使用新名称和数据重新创建标签
jsonb 列中的示例数据:
[
{ "tax": "yes", "tax_percent": 20, "used_when": "after" },
{ "tax": "no", "tax_percent": 20 },
{ "tax_percent": 20, "used_when": "before" }
]
现在:
“税”值需要从是更新 -> 真,否或空(不存在)意味着 -> 假
"used_when" 需要更新为 "using" 并且如果之后 -> true,如果之前 OR null(不存在)意味着 -> false
所以它看起来像:
[
{ "tax": true, "tax_percent": 20, "using": true },
{ "tax": false, "tax_percent": 20, "using": false },
{ "tax": false, "tax_percent": 20, "using": false }
]
这些值是可选的,因此并非所有条目都有它,而且这是数据库列中的单行,因此需要为每一行更新列中的数据。
UPDATE t -- 5
SET mydata = s.new_data
FROM (
SELECT
id,
json_agg((using_updated - 'used_when')::json) as new_data -- 4
FROM t,
json_array_elements(t.mydata) as elements, -- 1
jsonb_set(elements::jsonb, '{tax}', -- 2
CASE
WHEN elements ->> 'tax' = 'yes' THEN 'true'::jsonb
ELSE 'false'::jsonb
END
) as tax_updated,
jsonb_set(tax_updated::jsonb, '{using}', -- 3
CASE
WHEN tax_updated ->> 'used_when' = 'true' THEN 'true'::jsonb
ELSE 'false'::jsonb
END
) as using_updated
GROUP BY id
) s
WHERE s.id = t.id;
- 将所有数组元素提取为每条记录一个元素
2/3。现在您可以使用
jsonb_set()
在数组元素中插入新的或更新现有的属性。CASE
子句进行条件检查 - 消除剩余的
used_when
个元素。之后,您可以使用 json_agg 重新聚合更新的元素
- 做
UPDATE
如果您的数据类型为 json,您必须将类型转换为 jsonb,因为没有 json_set()
。如果没有,你当然可以忽略强制转换。
然而,正如@a_horse_with_no_name 正确提到的那样:您应该考虑不要将这些数据存储为纯 JSON 而是将它们提取到规范化的相对数据库 table 结构中,这使得事情更容易和更高效。