2012-11-28 18 views
11

Ho un campo di testo in un database (postgres 9.2.1) con un blob json in esso. Sembra qualcosa di simile a questo, tranne tutto su una sola riga, ovviamente:Aggiungi elemento all'oggetto JSON in Postgres

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

ho bisogno di aggiungere un elemento ad un array JSON in modo che assomiglia a questo:

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

io non sono come preoccupato per il posizionamento del nuovo elemento dell'array. Potrebbe essere dopo agency_name. C'è un modo semplice per farlo in Postgres?

+1

Prova a leggere http://stackoverflow.com/questions/10560394/how-do-i -query-using-fields-inside-the-new-postgresql-json-datatype. Potrebbe aiutarti. –

+0

Potrebbe appartenere al gruppo degli amministratori del database –

risposta

5

PostgreSQL non ha ancora molto in termini di funzioni di supporto JSON: tutto quello che posso vedere sono quelli come array_to_json, che potrebbe essere utile se ci fosse un modo corrispondente per convertire il JSON originale in un array, cosa che si potrebbe quindi manipola per aggiungere quell'elemento aggiuntivo prima di convertirlo nuovamente in JSON.

Forse la cosa migliore è usare un linguaggio PL per manipolare il JSON. Uno ovvio sarebbe PLV8, che fornisce funzionalità di programmazione JavaScript in PostgreSQL. Si potrebbe scrivere una funzione definita dall'utente in JavaScript che manipolare il blob JSON conseguenza:

Naturalmente, molte altre lingue PL come Java, Python o Perl possono essere altrettanto bravo a lavorare con dati JSON e possibilmente più facile da installare sul tuo sistema. Le funzioni definite dall'utente possono essere scritte in ognuna di queste se sono state configurate.

+2

Ovviamente non è la risposta che volevo, ma comunque gradevole. Grazie. – thepriebe

1

La versione 9.5 fornisce la funzione jsonb_set con create_missing = TRUE. In tutti gli altri casi, ricorrendo a un trucco per le informazioni aggiungendo:

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

Per aggiungere/sostituire nuovo valore con più corretto modo:

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) 

Per rimuovere chiave:

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

Grazie per la risposta. PostgreSQL 9.5 non era disponibile per me 2 anni fa. Da allora abbiamo iniziato a utilizzare il tipo di dati JSON che Postgres offre e usiamo PHP per codificare/decodificare. Quando JSON era solo una stringa nel DB, rendeva le cose un po 'più difficili. – thepriebe

5

Se aggiornamento a PG9.5.1, quindi è possibile utilizzare sql operare || per unire jsonb, esempio

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

tornerà {"a": 2, "b": 2}

Se non è possibile effettuare l'aggiornamento a pg9.5.1, IMHO, facendo il lavoro nel codice sarà una scelta migliore. È possibile analizzare la vecchia stringa jsonb come una mappa, quindi aggiornare la mappa, quindi convertire in stringa e aggiornare db-record.

1

Ho avuto esattamente questo problema. Questa soluzione è una manipolazione degli oggetti abbastanza "pura" e io preferisco le funzioni "sql" a plpgsql. La cosa principale è quello di disaggregare utilizzando json_each - dando un record - e quindi la creazione di un record dal

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

Come aggiunto all'inizio del documento? – igilfanov

+0

Mettere la sottoquery 'newvals' e UNION prima del ramo 'select json_val' della subquery 'to_rows', anziché dopo. –

5

Anche ho avuto lo stesso problema, ho voluto aggiungere dinamicamente nuovi elementi per jsonb [].

Assumere column_jsonb [] = [{ "name": "xyz", "età": "12"}]

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

Risultato: [{ "name": "xyz" , "età": "12"}, {"nome": "abc", "età": "22"}]

Problemi correlati