PostgreSQL 務實應用(四/5)JSON

JSON 可謂風靡互聯網,在數據交換使用上,其優點特別明顯,其結構簡潔、可讀易讀、形式靈活。不少 API 接口的數據都採用 JSON 來表示。html

PostgreSQL 對 JSON 提供了良好的支持。具體的相關函數可參考:JSON類型和函數sql

從使用的角度而言,我的以爲常見的應用場景爲:數據庫

  1. 讀取單個 JSON 的屬性值
  2. 遍歷單個 JSON 的全部屬性
  3. 遍歷一個 JSON 數組
  4. 建立一個 JSON 做爲返回值

之因此僅這些簡單的場景,緣由在於,在應用中使用高級語言處理 JSON 與在數據庫中使用那些高級的 JSON 函數相比,從操做上和可讀性上均爽不少。在不支持 JSON 的數據庫中,咱們也常使用單個文本字段存儲 JSON 字符串,而後在應用中加以解析處理。json

四個場景

咱們以如下的 JSON 字符串做爲輸入,來了解 PostgreSQL 在各場景中的應用實現。api

{
    "label": {
        "names": ["Amy", "Kala", "Lily"]
    },
    "color": "red",
    "count": 3
}

// 寫成一行便是
{"label":{"names":["Amy","Kala","Lily"]},"color":"red","count":3}

1.讀取屬性

首先,經過下面的表格,感覺一下 JavaScript 與 PostgreSQL 中讀取 color 屬性與 label 屬性中 names 的第二個值的形式。數組

讀屬性 JavaScript PostgreSQL
定義 var jsonObj = {"label":{"names":["Amy","Kala","Lily"]}, "color":"red","count":3}; jsonObj := '{"label":{"names":["Amy","Kala","Lily"]}, "color":"red","count":3}'::json;
讀取 JSON 的 color 屬性 jsonObj.color jsonObj -> 'color'
讀取 JSON 的 label 中 names 的第二個值 jsonObj.label.names[1] jsonObj -> 'label' -> 'names' -> 1

在 PostgreSQL 中咱們可使用如下語句逐層指定屬性路徑(屬性名稱須要使用字符串需單引號,數組索引使用數字)來獲取值:函數

-- 取得 color 屬性
SELECT '{"label":{"names":["Amy","Kala","Lily"]},"color":"red","count":3}'::json 
       -> 'color';

-- 取得 label 屬性下的 names 的第二個值
SELECT '{"label":{"names":["Amy","Kala","Lily"]},"color":"red","count":3}'::json 
       -> 'label' -> 'names' -> 1;

 此時取得的值仍然爲 json 類型,若是須要取得值的文本形式,則把最後一個 "->" 變成 "->>" 便可。ui

固然,路徑的表示,也能夠經過 #> '{label,names,1}' 的形式表示:code

SELECT '{"label":{"names":["Amy","Kala","Lily"]},"color":"red","count":3}'::json 
       #> '{label,names,1}';

 2.遍歷屬性

使用 json_each 函數,便可返回屬性鍵值對的數據集,數據集包括兩列,key 表示屬性,value 表示屬性值。以下語句輸出全部結果:htm

DO $$
DECLARE 
    lv_row record; 
    jsonObj json := '{"label":{"names":["Amy","Kala","Lily"]},"color":"red","count":3}'::json;
BEGIN   
    FOR lv_row IN SELECT * FROM json_each(jsonObj) LOOP  
        raise notice 'key is %, value is %', lv_row.key, lv_row.value;
    END LOOP;  
END $$;

輸出

NOTICE: key is label, value is {"names":["Amy","Kala","Lily"]}

NOTICE: key is color, value is "red"

NOTICE: key is count, value is 3

3.遍歷數組

經過使用 json_array_length 函數獲取數組的長度,而後根據索引遍歷整個數組便可。

DO $$
DECLARE 
    lv_row record; 
    lv_size int;
    jsonObj json := '{"label":{"names":["Amy","Kala","Lily"]},"color":"red","count":3}'::json;
BEGIN
    -- 取得label 下names 這個json數組
    jsonObj := jsonObj #> '{label,names}';
    -- 取得數組的長度
    lv_size := json_array_length(jsonObj);
    -- 按索引遍歷整個數組
    FOR i IN 0..lv_size-1 LOOP
        raise notice '%', jsonObj -> i;
    END LOOP;
END $$;

輸出:

NOTICE: "Amy"

NOTICE: "Kala"

NOTICE: "Lily" 

4.建立一個 JSON

使用 json_build_object 函數,傳遞  key, value 成對的參數便可建立一個 json,如如下語句造成一個 api 經常使用的返回執行狀況的 json。 

SELECT json_build_object('code', 200, 'err_msg', 'run success!');

應用示例

咱們以填寫學生地址爲例,傳遞給存儲過程的是一個 json 數組,每一個數組中的 json 對象包括了學生標識與地址信息。

如下語句建立數據表

-- student_id 學生標識, address 地址
CREATE TABLE student_address (student_id varchar(10) PRIMARY KEY, address varchar(100));

如下爲處理過程

CREATE OR REPLACE FUNCTION save_student_addresses_json( 
    v_array_json json)
    RETURNS json
    LANGUAGE 'plpgsql' 
AS $$
DECLARE 
    lv_row_json json; 
    lv_length int;
    lv_field_student_id varchar;
    lv_field_address    varchar;
BEGIN   
    -- 取得數組的長度
    lv_length := json_array_length(v_array_json);
    FOR i IN 0..lv_length-1 LOOP
        -- 取得第 i 行的 json 值
        lv_row_json := v_array_json -> i;
        lv_field_student_id := lv_row_json ->> 'student_id';
        lv_field_address := lv_row_json ->> 'address';

        -- 插入學生地址信息,若是存在則更新地址
        INSERT INTO student_address (student_id, address)
        VALUES (lv_field_student_id, lv_field_address)
            ON CONFLICT (student_id) 
        DO UPDATE SET address = excluded.address;
    END LOOP; 

    RETURN json_build_object(
        'err_code', 200, 
        'err_msg', '保存或更新 ' || lv_length || ' 條記錄'
    ); 
end 
$$

咱們執行如下操做

SELECT save_student_addresses_json(
    '[
     {"student_id":"01","address":"街道A"},
     {"student_id":"02","address":"街道B"}
    ]'
);

運行結果:{"err_code":200,"err_msg":"保存或更新 2 條記錄"}

小結一下

PostgreSQL 對 JSON 的操做支持特性很豐富,但文檔中那麼多函數一下映入眼簾,讓人以爲複雜凌亂。本文從簡單易理解的幾個應用場景出發,但願能先爽上一把,然後再細細深刻。I love PostgreSQL!

相關文章
相關標籤/搜索