Postgresql中JSONB数据类型修改
JSONB Data Type Modification in Postgresql
我对在 postgres 中修改 jsonb 数据类型有疑问
基本设置:-
数组=> ["1", "2", "3"]
现在我有一个带有 id
列和 jsonb 数据类型 列的 postgresql 数据库,我们只说 cards
.
id cards
-----+---------
1 {"1": 3, "4": 2}
这就是 table 中名为 test
的数据
问题:
如何将 id->1
的卡片从 {"1": 3, "4": 2}
转换为 {"1": 4, "4":2, "2": 1, "3": 1}
我希望如何发生变化:
从 array
开始,将 cards jsonb
中作为键存在的数组中存在的所有元素递增 1,从而将 {"1": 3} 更改为 {"1": 4 } 并将不存在的值作为键插入 cards jsonb
中,值为 1
从而将 {"1":4, "4":2} 更改为 {"1": 4, "4":2, "2":1, "3":1}
纯粹通过 postgres.
部分解决方案
我就我的问题向一位前辈寻求支持,我被告知:-
Roughly (names may differ): object keys to explode cards, array_elements to explode the array, left join them, do the calculation, re-aggregate the object. There may be a more direct way to do this but the above brute-force approach will work.
- 所以我尝试使用这两个函数
json_each_text()
、json_array_elements_text()
来完成它,但最终卡在了一半,而且我无法理解左连接两列的含义:-
SELECT jsonb_each_text(tester_cards) AS each_text, jsonb_array_elements_text('[["1", 1], ["2", 1], ["3", 1]]') AS array_elements FROM tester WHERE id=1;
TLDR;
- 更新语句,检查 jsonb 数据中是否存在数组 中的键范围 并自动递增 1 或分别将键插入到 jsonb 中共 1
现在看起来我好像在要求被喂食,但我真的还没有设法找到解决它的方法,因此非常感谢任何帮助
关键的见解是,使用 jsonb_each
和 jsonb_object_agg
您可以 round-trip 子查询中的 JSON 对象:
SELECT id, (
SELECT jsonb_object_agg(key, value)
FROM jsonb_each(cards)
) AS result
FROM test;
现在您可以 JOIN
这些 key-value 对与数组输入的 jsonb_array_elements
对。你的同事很接近,但不太正确:它需要一个完整的外部连接,而不仅仅是一个左(或右)连接来为你的输出获取所有需要的对象键,除非你的输入之一是另一个输入的子集。
SELECT id, (
SELECT jsonb_object_agg(COALESCE(obj_key, arr_value), …)
FROM jsonb_array_elements_text('["1", "2", "3"]') AS arr(arr_value)
FULL OUTER JOIN jsonb_each(cards) AS obj(obj_key, obj_value) ON obj_key = arr_value
) AS result
FROM test;
现在剩下的只是实际计算和转换为 UPDATE
语句:
UPDATE test
SET cards = (
SELECT jsonb_object_agg(
COALESCE(key, arr_value),
COALESCE(obj_value::int, 0) + (arr_value IS NOT NULL)::int
)
FROM jsonb_array_elements_text('["1", "2", "3"]') AS arr(arr_value)
FULL OUTER JOIN jsonb_each_text(cards) AS obj(key, obj_value) ON key = arr_value
);
我对在 postgres 中修改 jsonb 数据类型有疑问
基本设置:-
数组=> ["1", "2", "3"]
现在我有一个带有 id
列和 jsonb 数据类型 列的 postgresql 数据库,我们只说 cards
.
id cards
-----+---------
1 {"1": 3, "4": 2}
这就是 table 中名为 test
问题:
如何将 id->1
的卡片从 {"1": 3, "4": 2}
转换为 {"1": 4, "4":2, "2": 1, "3": 1}
我希望如何发生变化:
从 array
开始,将 cards jsonb
中作为键存在的数组中存在的所有元素递增 1,从而将 {"1": 3} 更改为 {"1": 4 } 并将不存在的值作为键插入 cards jsonb
中,值为 1
从而将 {"1":4, "4":2} 更改为 {"1": 4, "4":2, "2":1, "3":1}
纯粹通过 postgres.
部分解决方案
我就我的问题向一位前辈寻求支持,我被告知:-
Roughly (names may differ): object keys to explode cards, array_elements to explode the array, left join them, do the calculation, re-aggregate the object. There may be a more direct way to do this but the above brute-force approach will work.
- 所以我尝试使用这两个函数
json_each_text()
、json_array_elements_text()
来完成它,但最终卡在了一半,而且我无法理解左连接两列的含义:-
SELECT jsonb_each_text(tester_cards) AS each_text, jsonb_array_elements_text('[["1", 1], ["2", 1], ["3", 1]]') AS array_elements FROM tester WHERE id=1;
TLDR;
- 更新语句,检查 jsonb 数据中是否存在数组 中的键范围 并自动递增 1 或分别将键插入到 jsonb 中共 1
现在看起来我好像在要求被喂食,但我真的还没有设法找到解决它的方法,因此非常感谢任何帮助
关键的见解是,使用 jsonb_each
和 jsonb_object_agg
您可以 round-trip 子查询中的 JSON 对象:
SELECT id, (
SELECT jsonb_object_agg(key, value)
FROM jsonb_each(cards)
) AS result
FROM test;
现在您可以 JOIN
这些 key-value 对与数组输入的 jsonb_array_elements
对。你的同事很接近,但不太正确:它需要一个完整的外部连接,而不仅仅是一个左(或右)连接来为你的输出获取所有需要的对象键,除非你的输入之一是另一个输入的子集。
SELECT id, (
SELECT jsonb_object_agg(COALESCE(obj_key, arr_value), …)
FROM jsonb_array_elements_text('["1", "2", "3"]') AS arr(arr_value)
FULL OUTER JOIN jsonb_each(cards) AS obj(obj_key, obj_value) ON obj_key = arr_value
) AS result
FROM test;
现在剩下的只是实际计算和转换为 UPDATE
语句:
UPDATE test
SET cards = (
SELECT jsonb_object_agg(
COALESCE(key, arr_value),
COALESCE(obj_value::int, 0) + (arr_value IS NOT NULL)::int
)
FROM jsonb_array_elements_text('["1", "2", "3"]') AS arr(arr_value)
FULL OUTER JOIN jsonb_each_text(cards) AS obj(key, obj_value) ON key = arr_value
);