2012-11-28 11 views
11

Mam pole tekstowe w bazie danych (postgres 9.2.1) z json blob w nim. Wygląda to coś podobnego do tego, z wyjątkiem wszystko w jednej linii, oczywiście:Dodaj element do obiektu JSON w Postgresie

{ 
    "keyword": { 
    "checked": "1", 
    "label": "Keyword" 
    }, 
    "agency_name": { 
    "checked": "0", 
    "label": "Agency Name" 
    } 
} 

muszę dodać element do tablicy json tak, że wygląda tak:

{ 
    "keyword": { 
    "checked": "1", 
    "label": "Keyword" 
    }, 
    "something_new": { 
    "checked": "1", 
    "label": "Something New" 
    }, 
    "agency_name": { 
    "checked": "0", 
    "label": "Agency Name" 
    } 
} 

nie jestem tak zaniepokojony umieszczeniem nowego elementu tablicy. Może to być nazwa agencji. Czy istnieje prosty sposób na zrobienie tego w postgresie?

+1

Spróbuj przeczytać http://stackoverflow.com/questions/10560394/how-do-i -query-using-fields-inside-new-postgresql-json-datatype. To może ci pomóc. –

+0

Może należeć do grupy administratorów baz danych –

Odpowiedz

5

PostgreSQL nie ma jeszcze wiele funkcji pomocniczych JSON: wszystko, co widzę, to takie, jak array_to_json, które mogłoby być przydatne, gdyby istniał odpowiedni sposób konwersji oryginalnego JSON w tablicę, co wtedy manipuluj, aby dodać ten dodatkowy element przed konwersją z powrotem do JSON.

Prawdopodobnie najlepszą rzeczą jest użycie języka PL do manipulowania JSON. Jednym z oczywistych byłoby PLV8, który zapewnia funkcjonalność programowania JavaScript w PostgreSQL. Można by napisać funkcji zdefiniowanej przez użytkownika w JavaScript, która manipulowania blob JSON Odpowiednio:

oczywiście, wiele innych języków PL takie jak Java, Python lub Perl może być tak samo dobry praca z danymi JSON i prawdopodobnie łatwiejsza instalacja w twoim systemie. Funkcje zdefiniowane przez użytkownika mogą być zapisane w każdym z nich, jeśli masz je skonfigurowane.

+2

Oczywiście nie jest to odpowiedź, którą chciałem, ale nie mniej przyjemna. Dzięki. – thepriebe

1

Wersja 9.5 udostępnia funkcję jsonb_set z funkcją create_missing = TRUE. W innych przypadkach należy stosować następujące siekać do informacji jako załączniki:

SELECT (trim(trailing '}' from data::text) || ', "c":2}')::json 

Aby dodać/wymienić nową wartość używając bardziej poprawny sposób:

UPDATE t 
SET data=t3.data 

FROM t AS t1 
INNER JOIN 
(
    SELECT id, json_object_agg(t.k,t.v) 
    FROM 
    (
     SELECT * 
     FROM (SELECT id, json_object_keys(data) as k, data->json_object_keys(data) as v FROM t) as t2 
     WHERE t.k != 'c' 

     UNION ALL 
     SELECT id, 'c'::text as k, '"new value"'::json as v FROM t1 
    ) as t3 
    GROUP by id 
) as t4 ON (t1.id=t4.id) 

Aby klucz usunięcia:

UPDATE t 
SET data=t3.data 

FROM t AS t1 
INNER JOIN 
(
    SELECT id, json_object_agg(t.k,t.v) 
    FROM (SELECT id, json_object_keys(data) as k, data->json_object_keys(data) as v FROM t) as t2 
    WHERE t.k != 'c' 
    GROUP by id 
) as t4 ON (t1.id=t4.id) 
+0

Dzięki za odpowiedź. PostgreSQL 9.5 nie był dostępny dla mnie 2 lata temu. Od tego czasu zaczęliśmy używać typów danych JSON, które oferuje Postgres, i używamy PHP do kodowania/dekodowania. Kiedy JSON był tylko ciągiem znaków w DB, było to trochę trudniejsze. – thepriebe

5

Jeśli uaktualnij do PG9.5.1, następnie możesz użyć sql działa ||, aby połączyć jsonb, przykład

select '{"a":1}'::jsonb || '{"a":2, "b":2}'::jsonb 

powróci {"a": 2, "b": 2}

Jeśli nie można uaktualnić do pg9.5.1, IMHO, wykonując pracę w kodzie będzie lepszym wyborem. Możesz przeanalizować stary ciąg jsonb jako mapę, a następnie zaktualizować mapę, a następnie przekonwertować na ciąg znaków i zaktualizować rekord db.

1

Miałem dokładnie ten problem. To rozwiązanie jest dość "czystą" manipulacją obiektami i wolę funkcje "sql" od plpgsql. Najważniejsze jest to, aby odłączyć się używając json_each - co daje rekord - a następnie tworząc rekord z

CREATE OR REPLACE FUNCTION json_extend_object(
    input_object json, 
    append_key text, 
    append_object json) 
    RETURNS json AS 
$BODY$ 
    select json_object_agg (((json_val)::record).key, ((json_val)::record).value) 
    from (
     select json_val 
     from (select json_each (input_object) as json_val) disaggr 
     where ((json_val::record).key != append_key) 
     union 
     select newvals 
     from (
      select append_key, append_object 
     ) newvals 
    ) to_rows; 
$BODY$ 
    LANGUAGE sql IMMUTABLE 
    ; 
+0

Jak dodano na początku dokumentu? – igilfanov

+0

Umieść podzapytanie "newvals" i UNION przed podkatalogiem "select json_val" podkwerendy "to_rows" zamiast po. –

5

Nawet miałem ten sam problem, chciałem dynamicznie dołączać nowe elementy do jsonb [].

Załóżmy column_jsonb [] = [{ "Nazwa": "xyz", "wiek": "12"}]

UPDATE table_name 
    SET column_jsonb[] = array_append(column_jsonb[],'{"name":"abc","age":"22"}'); 

Wynik: [{ "Nazwa": "xyz" , "age": "12"}, {"name": "abc", "age": "22"}]