PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Bagaimana cara mengubah bidang di dalam tipe data PostgreSQL JSON yang baru?

Perbarui :Dengan PostgreSQL 9.5, ada beberapa jsonb fungsi manipulasi dalam PostgreSQL itu sendiri (tetapi tidak untuk json; gips diperlukan untuk memanipulasi json nilai).

Menggabungkan 2 (atau lebih) objek JSON (atau menggabungkan array):

SELECT jsonb '{"a":1}' || jsonb '{"b":2}', -- will yield jsonb '{"a":1,"b":2}'
       jsonb '["a",1]' || jsonb '["b",2]'  -- will yield jsonb '["a",1,"b",2]'

Jadi, menyetel kunci sederhana dapat dilakukan dengan menggunakan:

SELECT jsonb '{"a":1}' || jsonb_build_object('<key>', '<value>')

Dimana <key> harus berupa string, dan <value> bisa apa saja jenis to_jsonb() menerima.

Untuk menyetel nilai jauh di dalam hierarki JSON , jsonb_set() fungsi yang dapat digunakan:

SELECT jsonb_set('{"a":[null,{"b":[]}]}', '{a,1,b,0}', jsonb '{"c":3}')
-- will yield jsonb '{"a":[null,{"b":[{"c":3}]}]}'

Daftar parameter lengkap jsonb_set() :

jsonb_set(target         jsonb,
          path           text[],
          new_value      jsonb,
          create_missing boolean default true)

path dapat berisi indeks array JSON juga &bilangan bulat negatif yang muncul di sana dihitung dari akhir array JSON. Namun, indeks array JSON yang tidak ada tetapi positif akan menambahkan elemen ke akhir array:

SELECT jsonb_set('{"a":[null,{"b":[1,2]}]}', '{a,1,b,1000}', jsonb '3', true)
-- will yield jsonb '{"a":[null,{"b":[1,2,3]}]}'

Untuk memasukkan ke dalam larik JSON (sambil mempertahankan semua nilai asli) , jsonb_insert() fungsi dapat digunakan (di 9.6+; hanya fungsi ini, di bagian ini ):

SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,b,0}', jsonb '2')
-- will yield jsonb '{"a":[null,{"b":[2,1]}]}', and
SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,b,0}', jsonb '2', true)
-- will yield jsonb '{"a":[null,{"b":[1,2]}]}'

Daftar parameter lengkap jsonb_insert() :

jsonb_insert(target       jsonb,
             path         text[],
             new_value    jsonb,
             insert_after boolean default false)

Sekali lagi, bilangan bulat negatif yang muncul di path hitung dari akhir array JSON.

Jadi, f.ex. menambahkan ke akhir array JSON dapat dilakukan dengan:

SELECT jsonb_insert('{"a":[null,{"b":[1,2]}]}', '{a,1,b,-1}', jsonb '3', true)
-- will yield jsonb '{"a":[null,{"b":[1,2,3]}]}', and

Namun, fungsi ini bekerja sedikit berbeda (dari jsonb_set() ) ketika path di target adalah kunci objek JSON. Dalam hal ini, itu hanya akan menambahkan pasangan nilai kunci baru untuk objek JSON saat kunci tidak digunakan. Jika digunakan, itu akan menimbulkan kesalahan:

SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,c}', jsonb '[2]')
-- will yield jsonb '{"a":[null,{"b":[1],"c":[2]}]}', but
SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,b}', jsonb '[2]')
-- will raise SQLSTATE 22023 (invalid_parameter_value): cannot replace existing key

Menghapus kunci (atau indeks) dari objek JSON (atau, dari array) dapat dilakukan dengan - operator:

SELECT jsonb '{"a":1,"b":2}' - 'a', -- will yield jsonb '{"b":2}'
       jsonb '["a",1,"b",2]' - 1    -- will yield jsonb '["a","b",2]'

Menghapus, dari dalam hierarki JSON dapat dilakukan dengan #- operator:

SELECT '{"a":[null,{"b":[3.14]}]}' #- '{a,1,b,0}'
-- will yield jsonb '{"a":[null,{"b":[]}]}'

Untuk 9,4 , Anda dapat menggunakan versi modifikasi dari jawaban asli (di bawah), tetapi alih-alih menggabungkan string JSON, Anda dapat menggabungkan menjadi objek json secara langsung dengan json_object_agg() .

Jawaban asli :Itu mungkin (tanpa plpython atau plv8) dalam SQL murni juga (tetapi membutuhkan 9.3+, tidak akan berfungsi dengan 9.2)

CREATE OR REPLACE FUNCTION "json_object_set_key"(
  "json"          json,
  "key_to_set"    TEXT,
  "value_to_set"  anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')::json
  FROM (SELECT *
          FROM json_each("json")
         WHERE "key" <> "key_to_set"
         UNION ALL
        SELECT "key_to_set", to_json("value_to_set")) AS "fields"
$function$;

SQLFiddle

Sunting :

Versi, yang menyetel beberapa kunci &nilai:

CREATE OR REPLACE FUNCTION "json_object_set_keys"(
  "json"          json,
  "keys_to_set"   TEXT[],
  "values_to_set" anyarray
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')::json
  FROM (SELECT *
          FROM json_each("json")
         WHERE "key" <> ALL ("keys_to_set")
         UNION ALL
        SELECT DISTINCT ON ("keys_to_set"["index"])
               "keys_to_set"["index"],
               CASE
                 WHEN "values_to_set"["index"] IS NULL THEN 'null'::json
                 ELSE to_json("values_to_set"["index"])
               END
          FROM generate_subscripts("keys_to_set", 1) AS "keys"("index")
          JOIN generate_subscripts("values_to_set", 1) AS "values"("index")
         USING ("index")) AS "fields"
$function$;

Edit 2 :seperti yang dicatat oleh @ErwinBrandstetter, fungsi-fungsi di atas berfungsi seperti yang disebut UPSERT (memperbarui bidang jika ada, menyisipkan jika tidak ada). Berikut adalah variannya, yang hanya UPDATE :

CREATE OR REPLACE FUNCTION "json_object_update_key"(
  "json"          json,
  "key_to_set"    TEXT,
  "value_to_set"  anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT CASE
  WHEN ("json" -> "key_to_set") IS NULL THEN "json"
  ELSE (SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')
          FROM (SELECT *
                  FROM json_each("json")
                 WHERE "key" <> "key_to_set"
                 UNION ALL
                SELECT "key_to_set", to_json("value_to_set")) AS "fields")::json
END
$function$;

Edit 3 :Ini adalah varian rekursif, yang dapat disetel (UPSERT ) nilai daun (dan menggunakan fungsi pertama dari jawaban ini), terletak di jalur kunci (di mana kunci hanya dapat merujuk ke objek dalam, array dalam tidak didukung):

CREATE OR REPLACE FUNCTION "json_object_set_path"(
  "json"          json,
  "key_path"      TEXT[],
  "value_to_set"  anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT CASE COALESCE(array_length("key_path", 1), 0)
         WHEN 0 THEN to_json("value_to_set")
         WHEN 1 THEN "json_object_set_key"("json", "key_path"[l], "value_to_set")
         ELSE "json_object_set_key"(
           "json",
           "key_path"[l],
           "json_object_set_path"(
             COALESCE(NULLIF(("json" -> "key_path"[l])::text, 'null'), '{}')::json,
             "key_path"[l+1:u],
             "value_to_set"
           )
         )
       END
  FROM array_lower("key_path", 1) l,
       array_upper("key_path", 1) u
$function$;

Diperbarui:Menambahkan fungsi untuk mengganti kunci bidang json yang ada dengan kunci lain yang diberikan. Dapat berguna untuk memperbarui tipe data dalam migrasi atau skenario lain seperti perubahan struktur data.

CREATE OR REPLACE FUNCTION json_object_replace_key(
    json_value json,
    existing_key text,
    desired_key text)
  RETURNS json AS
$BODY$
SELECT COALESCE(
(
    SELECT ('{' || string_agg(to_json(key) || ':' || value, ',') || '}')
    FROM (
        SELECT *
        FROM json_each(json_value)
        WHERE key <> existing_key
        UNION ALL
        SELECT desired_key, json_value -> existing_key
    ) AS "fields"
    -- WHERE value IS NOT NULL (Actually not required as the string_agg with value's being null will "discard" that entry)

),
    '{}'
)::json
$BODY$
  LANGUAGE sql IMMUTABLE STRICT
  COST 100;

Perbarui :fungsi dipadatkan sekarang.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Temukan Induk secara Rekursif menggunakan Query

  2. Pemutakhiran Otomatis Cluster PostgreSQL Hampir-Nol di Cloud (Bagian I)

  3. Cara Mengubah Pengguna menjadi Pengguna Super di PostgreSQL

  4. Kembalikan Cap Waktu Unix di PostgreSQL

  5. Bagaimana cara mengubah kata sandi pengguna PostgreSQL?