PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jak zmodyfikować pola w nowym typie danych PostgreSQL JSON?

Aktualizacja :W PostgreSQL 9.5 jest kilka jsonb funkcjonalność manipulacji w samym PostgreSQL (ale żadna dla json; rzutowania są wymagane do manipulowania json wartości).

Scalanie 2 (lub więcej) obiektów JSON (lub łączenie tablic):

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]'

A więc ustawienie prostego klucza można to zrobić za pomocą:

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

Gdzie powinien być ciągiem, a może być dowolnym typem to_jsonb() akceptuje.

Do ustawienia wartości głęboko w hierarchii JSON , jsonb_set() można użyć funkcji:

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

Pełna lista parametrów jsonb_set() :

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

ścieżka może zawierać również indeksy tablic JSON i ujemne liczby całkowite, które się tam pojawiają, liczą się od końca tablic JSON. Jednak nieistniejący, ale dodatni indeks tablicy JSON doda element na końcu tablicy:

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

Do wstawiania do tablicy JSON (przy zachowaniu wszystkich oryginalnych wartości) , jsonb_insert() można użyć funkcji (w wersji 9.6+; tylko ta funkcja, w tej sekcji ):

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]}]}'

Pełna lista parametrów jsonb_insert() :

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

Ponownie, ujemne liczby całkowite, które pojawiają się w ścieżce liczyć od końca tablic JSON.

Tak więc np. dołączenie na końcu tablicy JSON można wykonać za pomocą:

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

Jednak ta funkcja działa nieco inaczej (niż jsonb_set() ) gdy ścieżka w celu jest kluczem obiektu JSON. W takim przypadku doda nową parę klucz-wartość dla obiektu JSON tylko wtedy, gdy klucz nie jest używany. Jeśli zostanie użyty, zgłosi błąd:

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

Usuwanie klucza (lub indeksu) z obiektu JSON (lub z tablicy) można to zrobić za pomocą - 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]'

Usuwanie z głębi hierarchii JSON można to zrobić za pomocą #- operator:

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

Dla 9.4 , możesz użyć zmodyfikowanej wersji oryginalnej odpowiedzi (poniżej), ale zamiast agregować ciąg JSON, możesz agregować do obiektu json bezpośrednio za pomocą json_object_agg() .

Oryginalna odpowiedź :Jest to możliwe (bez plpythona lub plv8) również w czystym SQL (ale wymaga wersji 9.3+, nie będzie działać z wersją 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

Edytuj :

Wersja, która ustawia wiele kluczy i wartości:

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$;

Edytuj 2 :jak zauważył @ErwinBrandstetter, powyższe funkcje działają jak tak zwany UPSERT (aktualizuje pole, jeśli istnieje, wstawia, jeśli nie istnieje). Oto wariant, który tylko 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$;

Edytuj 3 :Oto wariant rekurencyjny, który można ustawić (UPSERT ) wartość liścia (i używa pierwszej funkcji z tej odpowiedzi), znajdującą się na ścieżce klucza (gdzie klucze mogą odnosić się tylko do obiektów wewnętrznych, wewnętrzne tablice nie są obsługiwane):

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$;

Zaktualizowano:Dodano funkcję zastępowania istniejącego klucza pola json innym podanym kluczem. Może być przydatny do aktualizacji typów danych w migracjach lub innych scenariuszach, takich jak zmiana struktury danych.

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;

Aktualizacja :funkcje są teraz kompaktowane.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PHP nie ładuje php_pgsql.dll w systemie Windows

  2. Konfiguracja i konserwacja replikacji PostgreSQL przy użyciu Ansible

  3. Postgresql wymusza unikalną dwukierunkową kombinację kolumn

  4. Liquibase/PostgreSQL:jak prawidłowo zachować wielkość liter?

  5. PostgreSql WSTAW Z WYBRANEGO ID POWRACAJĄCEGO