前言
最近上有這樣一個問題, 項目上線之後, 上下一個版本的時候, 可能需要升級一部分的配置數據 之類的東西
而 這部分的數據 有些可能是存放在 json數組 字段裏面的, postgresql 裏面是 json, jsonb 類型
關於json, jsonb 的相關基礎介紹, 可以參見官方文檔 : http://www.postgres.cn/docs/10/datatype-json.html
然後 有這樣的需求, 就是 需要更新 json 數組裏面的某一個屬性爲 xx 的元素, 更新這個元素的其他屬性
類似於有一個 List<User> friends, 需要更新 其中 name 爲 hx 的User 的 age 爲 43
這種操作, 在網上搜索了一下 似乎相關的資料不是太多啊, 大多數文章介紹的就是 官方文檔上面的一些 簡單的示例, 沒辦法 只能自己來踩坑摸索了
以下 sql 使用到的 postgresql 版本如下
select version();
PostgreSQL 11.4 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609, 64-bit
參考代碼
相關表結構, 以及基礎數據準備如下
## 測試建表語句
CREATE TABLE "public"."user" (
"id" varchar(64) COLLATE "default" NOT NULL,
"code" varchar(32) COLLATE "default" DEFAULT ''::character varying,
"friends" jsonb,
CONSTRAINT "baseapp_bank_pkey" PRIMARY KEY ("id")
)
WITH (OIDS=FALSE)
;
ALTER TABLE "public"."user" OWNER TO "postgres";
COMMENT ON TABLE "public"."user" IS '用戶';
COMMENT ON COLUMN "public"."user"."code" IS '編碼';
COMMENT ON COLUMN "public"."user"."friends" IS '朋友列表';
# 添加測試數據
delete from "public"."user";
INSERT INTO "public"."user" ("id", "code", "friends") VALUES ('1', 'dzt', '[{"age": "33", "code": "hx"}, {"age": "85", "code": "doit"}]');
INSERT INTO "public"."user" ("id", "code", "friends") VALUES ('2', 'hx', '[{"age": "36", "code": "dzt"}, {"age": "85", "code": "doit"}]');
INSERT INTO "public"."user" ("id", "code", "friends") VALUES ('3', 'doit', '[{"age": "36", "code": "dzt"}, {"age": "33", "code": "hx"}]');
初始化了三個用戶, 這三個用戶是彼此的朋友, 一個 dzt, 一個 hx, 一個 doit
現在我們想把 friends 這一列的裏面的 code 爲 hx 的元素, age 更新爲 43
查詢更新結果
select u.id, u.code,
jsonb_set(
friends,
concat(
'{',
(array_position(array(select jsonb_array_elements_text(friends) from "public"."user" where id = u.id),
(select jae::text from (
select jsonb_array_elements(friends) as jae from "public"."user" where id = u.id
) as tmp
where jae::jsonb->>'code' = 'hx')
) - 1),
'}'
)::_text,
-- '{28}',
'{"age": "43", "code": "hx"}'::jsonb
)
from "public"."user" as u where 1 = 1
and (array_position(array(select jsonb_array_elements_text(friends) from "public"."user" where id = u.id),
(select jae::text from (
select jsonb_array_elements(friends) as jae from "public"."user" where id = u.id
) as tmp
where jae::jsonb->>'code' = 'hx')
) - 1) >= 0
;
執行結果如下
得到了我們期望的結果, 我們期望 更新 dzt, doit 的 User 的 friends 列 並將其中的 code 爲 hx 的用戶 age 更新爲 43
相信到這裏, 對應的 update 語句就更好寫了吧
這裏面將 array_position 的結果 -1, 是因爲 數組下標是以 1 開始的
這裏使用到的相關基礎知識整理如下
---- common usage
-- 1. 更新給定的路徑的 數據的值
select id, code, jsonb_set(friends, '{0, hobby}', '"game"', true) from "public"."user" where 1 = 1;
-- 2. 將json數組轉換爲 array
select id, code, jsonb_array_elements(friends) from "public"."user" where code = 'dzt';
select id, code, array(select jsonb_array_elements(friends)) from "public"."user" where code = 'dzt';
-- 3. 查詢給定的 報表維度 的 name 爲給定的 key 的配置信息
select * from (
select id, code, jsonb_array_elements(friends) as jae from "public"."user" where 1 = 1
) as tmp
where jae::jsonb->>'code' = 'hx';
相關執行結果如下
引用
postgresql數組操作符與函數
https://blog.csdn.net/pg_hgdb/article/details/79483767
關於pgsql 的json 和jsonb 的數據處理筆記
https://www.cnblogs.com/liuchuanfeng/p/8510270.html
postgreSQL查詢結果添加一個額外的自增序列
https://blog.csdn.net/camillect/article/details/85207934
postgresql 官方文檔相關
8.14. JSON 類型
http://www.postgres.cn/docs/10/datatype-json.html
8.15. 數組
http://www.postgres.cn/docs/10/arrays.html#ARRAYS-ACCESSING
9.15. JSON 函數和操作符
http://www.postgres.cn/docs/10/functions-json.html
9.18. 數組函數和操作符
http://www.postgres.cn/docs/10/functions-array.html