關於pgsql 的json 和jsonb 的數據處理筆記
1. json 和jsonb 區別
兩者從用戶操作的角度來說沒有區別,區別主要是存儲和讀取的系統處理(預處理)和耗時方面有區別。json寫入快,讀取慢,jsonb寫入慢,讀取快。
2. 常用的操作符
操作符:
-> // 右邊傳入整數(針對純數組),獲取數組的第n個元素,n從0開始算,返回值為json
示例: select '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json->2 // 輸出 {"c":"baz"}
-> // 右邊傳入鍵值(針對關聯數組),獲取數組的第n個元素,n從0開始算,返回值為json
示例: select '{"a": {"b":"foo"}, "c":{"a": "aaa"}}'::json->'a' // 輸出 {"b":"foo"}
->> // 右邊傳入整數(針對純數組),獲取數組的第n個元素,n從0開始算,返回值為文本
示例: select '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json->>2 // 輸出 {"c":"baz"}
->> // 右邊傳入鍵值(針對關聯數組),獲取數組的第n個元素,n從0開始算,返回值為文本
示例: select '{"a": {"b":"foo"}, "c":{"a": "aaa"}}'::json->>'a' // 輸出 {"b":"foo"}
#> // 獲取json子對象,傳入數組,返回json
示例: select '{"a": {"b":{"c": "foo"}}}'::json#> '{a,b}' // 輸出 {"c": "foo"}
#>> // 獲取json子對象並轉換為文本,傳入數組,返回文本
示例: select '{"a": {"b":{"c": "foo"}}}'::json#>> '{a,b}' // 輸出 {"c": "foo"}
3. 操作函數
目前pgsql版本提供了兩套函數分別處理,可以通用,名稱也差不多,比如 json_each 和 jsonb_each , json_array_elements 和 jsonb_array_elements 。
json相關的處理函數比較多,常用的有如下三個,這三個基本夠用了
json_object_keys // 返回json的鍵(多層只返回第一層),該函數不能用於純數組.
json_array_elements // 提取轉換純數組元素
json_extract_path // 返回JSON值所指向的某個鍵元素(相當於 #> 操作符),該函數不能直接操作純數組。
需要注意的是如果你創建字段用的是json就用json相關函數,如果創建字段用的是jsonb就用jsonb相關函數。
json_object_keys 函數示例:
select json_object_keys ('
{
"goods":
[
{"id": "676a13d3-0225-4431-b858-678c3cfeab74", "weight": "1", "quantity": "9999999"},
{"id": "111a13d3-0225-4431-b858-678c3cfeab75", "weight": "2", "quantity": "33"}
],
"quantity": "10"
}
')
輸出:
json_object_keys 函數示例:
select json_object_keys ('
[
{"id": "676a13d3-0225-4431-b858-678c3cfeab74", "weight": "1", "quantity": "9999999"},
{"id": "111a13d3-0225-4431-b858-678c3cfeab75", "weight": "2", "quantity": "33"}
],
')
輸出:
ERROR: cannot call json_object_keys on an array // 不能用於數組
json_array_elements 函數 示例:
select json_array_elements ('
[
{"id": "676a13d3-0225-4431-b858-678c3cfeab74", "weight": "1", "quantity": "9999999"},
{"id": "111a13d3-0225-4431-b858-678c3cfeab75", "weight": "2", "quantity": "33"},
{"id": "111a13d3-0225-4431-b858-678c3cfea999", "weight": "3", "quantity": "11"}
]
')
我們看到json數據被分離成三條記錄,這時我們就可以對其進行查詢操作,
比如查詢是否包含了weight=3的數據。
select * from json_array_elements ('
[
{"id": "676a13d3-0225-4431-b858-678c3cfeab74", "weight": "1", "quantity": "9999999"},
{"id": "111a13d3-0225-4431-b858-678c3cfeab75", "weight": "2", "quantity": "33"},
{"id": "111a13d3-0225-4431-b858-678c3cfea999", "weight": "3", "quantity": "11"}
]
') as jae
where jae::jsonb->>'weight' = '3'
#輸出:
我們看到這樣就可以到對json數據內部進行查詢了。
json_extract_path 函數示例:
比如要獲取鍵 ‘goods’ 的值:
{
"goods":
[
{"id": "676a13d3-0225-4431-b858-678c3cfeab74", "weight": "1", "quantity": "9999999"},
{"id": "111a13d3-0225-4431-b858-678c3cfeab75", "weight": "2", "quantity": "33"}
],
"quantity": {"max": "150", "min": "2"}
}
select json_extract_path ('
{
"goods":
[
{"id": "676a13d3-0225-4431-b858-678c3cfeab74", "weight": "1", "quantity": "9999999"},
{"id": "111a13d3-0225-4431-b858-678c3cfeab75", "weight": "2", "quantity": "33"}
],
"quantity": {"max": "150", "min": "2"}
}
' , 'goods' ) ; // 第二個參數表示獲取鍵為goods的值
#輸出:
json_extract_path 函數和 pgsql 提供的操作符 #> 是一樣的。
select ('
{
"goods":
[
{"id": "676a13d3-0225-4431-b858-678c3cfeab74", "weight": "1", "quantity": "9999999"},
{"id": "111a13d3-0225-4431-b858-678c3cfeab75", "weight": "2", "quantity": "33"}
],
"quantity": {"max": "150", "min": "2"}
}
') ::json #> '{goods}'
兩者的輸出是一致的。
同樣我們要輸出 鍵quantity 下鍵max 的值:
select json_extract_path ('
{
"goods":
[
{"id": "676a13d3-0225-4431-b858-678c3cfeab74", "weight": "1", "quantity": "9999999"},
{"id": "111a13d3-0225-4431-b858-678c3cfeab75", "weight": "2", "quantity": "33"}
],
"quantity": {"max": "150", "min": "2"}
}
' , 'quantity','max' ) ;
-- 或
select ('
{
"goods":
[
{"id": "676a13d3-0225-4431-b858-678c3cfeab74", "weight": "1", "quantity": "9999999"},
{"id": "111a13d3-0225-4431-b858-678c3cfeab75", "weight": "2", "quantity": "33"}
],
"quantity": {"max": "150", "min": "2"}
}
') ::json #> '{quantity, max}'
兩者輸出是一樣的。
這幾個函數是可以聯合使用的。
比如我們要查詢 鍵“goods” 下weight =2 的id 和quantity 值,語句如下:
select jae::json->>'id' as id, jae::json->>'quantity' as quantity from json_array_elements (
json_extract_path ('
{
"goods":
[
{"id": "676a13d3-0225-4431-b858-678c3cfeab74", "weight": "1", "quantity": "9999999"},
{"id": "111a13d3-0225-4431-b858-678c3cfeab75", "weight": "2", "quantity": "33"}
],
"quantity": {"max": "150", "min": "2"}
}
' , 'goods' ) ) as jae where jae::json->> 'weight' = '2'
#輸出:
上述的json語句我們可以當做字段來使用,就相當於對表記錄進行操作了。
接下來我們同個一個例子講解json在表中的用法:
示例:查詢表中jsonb_msg字段中goods下id=1003和1002的記錄,表中輸入如下圖:
sql查詢語句:
select name,* from upgrade_test.test1 test
where
( select count(*) from jsonb_array_elements (
jsonb_extract_path(test.json_msg , 'goods' ) ) as jae where jae::json->> 'id' in ('1001','1003') ) > 0 ;
#輸出:
效率還行:
Total query runtime: 11 msec
檢索到 2 行。
官方文檔頁:
https://www.postgresql.org/docs/9.4/static/functions-json.html