Come posso modificare i campi all'interno del nuovo tipo di dati JSON PostgreSQL?


235

Con postgresql 9.3 posso SELEZIONARE campi specifici di un tipo di dati JSON, ma come si modificano usando UPDATE? Non riesco a trovare alcun esempio di ciò nella documentazione di postgresql, o ovunque online. Ho provato l'ovvio:

postgres=# create table test (data json);
CREATE TABLE
postgres=# insert into test (data) values ('{"a":1,"b":2}');
INSERT 0 1
postgres=# select data->'a' from test where data->>'b' = '2';
 ?column?
----------
 1
(1 row)
postgres=# update test set data->'a' = to_json(5) where data->>'b' = '2';
ERROR:  syntax error at or near "->"
LINE 1: update test set data->'a' = to_json(5) where data->>'b' = '2...

Risposte:


331

Aggiornamento : Con PostgreSQL 9.5 ci sono alcune jsonbfunzionalità di manipolazione all'interno di PostgreSQL stesso (ma nessuna per json; i cast sono necessari per manipolare i jsonvalori).

Unione di 2 (o più) oggetti JSON (o concatenazione di matrici):

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

Pertanto, l' impostazione di una chiave semplice può essere eseguita utilizzando:

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

Dove <key>dovrebbe essere stringa e <value>può essere qualunque tipo to_jsonb()accetta.

Per impostare un valore in profondità in una gerarchia JSON , è jsonb_set()possibile utilizzare la funzione:

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

Elenco completo dei parametri di jsonb_set():

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

pathpuò contenere anche indici di array JSON e numeri interi negativi che vengono visualizzati contano dalla fine degli array JSON. Tuttavia, un indice di array JSON inesistente ma positivo aggiungerà l'elemento alla fine dell'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]}]}'

Per l' inserimento nell'array JSON (pur mantenendo tutti i valori originali) , è jsonb_insert()possibile utilizzare la funzione ( in 9.6+; solo questa funzione, in questa sezione ):

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

Elenco completo dei parametri di jsonb_insert():

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

Ancora una volta, numeri interi negativi che appaiono in pathconteggio dalla fine delle matrici JSON.

Quindi, f.ex. l'aggiunta alla fine di un array JSON può essere eseguita con:

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

Tuttavia, questa funzione funziona in modo leggermente diverso (rispetto a jsonb_set()) quando pathin targetè la chiave di un oggetto JSON. In tal caso, aggiungerà una nuova coppia chiave-valore per l'oggetto JSON solo quando la chiave non viene utilizzata. Se viene utilizzato, genererà un errore:

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

L'eliminazione di una chiave (o di un indice) da un oggetto JSON (o, da un array) può essere eseguita con l' -operatore:

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

L'eliminazione, dal profondo di una gerarchia JSON, può essere eseguita con l' #-operatore:

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

Per 9.4 , è possibile utilizzare una versione modificata della risposta originale (di seguito), ma invece di aggregare una stringa JSON, è possibile aggregare direttamente in un oggetto JSON json_object_agg().

Risposta originale : è possibile (senza plpython o plv8) anche in SQL puro (ma necessita di 9.3+, non funzionerà con 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

Modifica :

Una versione, che imposta più chiavi e valori:

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

Modifica 2 : come notato da @ErwinBrandstetter, queste funzioni sopra funzionano come una cosiddetta UPSERT(aggiorna un campo se esiste, inserisce se non esiste). Ecco una variante, che solo 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$;

Modifica 3 : Ecco la variante ricorsiva, che può impostare ( UPSERT) un valore foglia (e utilizza la prima funzione da questa risposta), situata in un percorso chiave (dove le chiavi possono riferirsi solo a oggetti interni, array interni non supportati):

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

Aggiornamento : le funzioni sono ora compattate.


5
Ho provato la tua funzione plpgsql, ma non sono sicuro di come usarla - vedo un errore quando provo select json_object_set_key((select data from test where data->>'b' = '2'), 'b', 'two'); il messaggio di errore è ERROR: could not determine polymorphic type because input has type "unknown"
user9645

1
Questo esegue l'equivalente di an UPSERT, non an UPDATE. Se la chiave non esiste ancora nel campo json, viene aggiunta. Guarda questa domanda correlata per un effettivo UPDATE: stackoverflow.com/questions/7711432/… (Questo è per un tipo composito, ma il principio è simile per json.)
Erwin Brandstetter

1
@ErwinBrandstetter è vero, ma in json un UPSERT di solito più generale di una modifica del tipo AGGIORNAMENTO (considera f.ex. sqlfiddle.com/#!15/d41d8/2897 ) - Ho interpretato la domanda originale come si modifica loro (colonne json) usando un'istruzione UPDATE? - inoltre una singola condizione potrebbe trasformarla in AGGIORNAMENTO.
Pozs

1
Molto utile e completo ora.
Erwin Brandstetter,

1
@maxhud che dipende dal client (o dalla libreria client che usi). Se puoi, usa tipi espliciti (PostgreSQL può indovinare i tipi nelle query parametrizzate, ma di solito non funziona bene con le funzioni polimorfiche). Ma almeno, puoi usare cast espliciti, come $2::text.
Pozs

98

Con 9.5 usa jsonb_set-

UPDATE objects
SET body = jsonb_set(body, '{name}', '"Mary"', true)
WHERE id = 1; 

dove body è un tipo di colonna jsonb.


Ciao, perché non posso usare uppercosì: update objects set body=jsonb_set(body, '{name}', upper('"Mary"'), true) where id=1;non riconosce, o come posso ottenere lo stesso comportamento? grazie
Rafael Capucho il

1
Se il valore che voglio impostare è una sottostringa di un'altra colonna anziché "Mary", come lo farei?
Andrew,

58

Con Postgresql 9.5 puoi farlo seguendo-

UPDATE test
SET data = data - 'a' || '{"a":5}'
WHERE data->>'b' = '2';

O

UPDATE test
SET data = jsonb_set(data, '{a}', '5'::jsonb);

Qualcuno ha chiesto come aggiornare molti campi nel valore jsonb contemporaneamente. Supponiamo di creare una tabella:

CREATE TABLE testjsonb ( id SERIAL PRIMARY KEY, object JSONB );

Quindi INSERIAMO una riga sperimentale:

INSERT INTO testjsonb
VALUES (DEFAULT, '{"a":"one", "b":"two", "c":{"c1":"see1","c2":"see2","c3":"see3"}}');

Quindi AGGIORNIAMO la riga:

UPDATE testjsonb SET object = object - 'b' || '{"a":1,"d":4}';

Che fa quanto segue:

  1. Aggiorna il campo a
  2. Rimuove il campo b
  3. Aggiungi il campo d

Selezione dei dati:

SELECT jsonb_pretty(object) FROM testjsonb;

Si tradurrà in:

      jsonb_pretty
-------------------------
 {                      +
     "a": 1,            +
     "c": {             +
         "c1": "see1",  +
         "c2": "see2",  +
         "c3": "see3",  +
     },                 +
     "d": 4             +
 }
(1 row)

Per aggiornare il campo all'interno, non utilizzare l'operatore concat ||. Utilizzare invece jsonb_set. Che non è semplice:

UPDATE testjsonb SET object =
jsonb_set(jsonb_set(object, '{c,c1}','"seeme"'),'{c,c2}','"seehim"');

Utilizzando l'operatore concat per {c, c1} ad esempio:

UPDATE testjsonb SET object = object || '{"c":{"c1":"seedoctor"}}';

Rimuoverà {c, c2} e {c, c3}.

Per maggiore potenza, cerca la documentazione delle funzioni json di postgresql . Uno potrebbe essere interessato #-all'operatore, alla jsonb_setfunzione e anche alla jsonb_insertfunzione.


e se devo aggiornare due campi, qual è la sintassi?
Sunil Garg,

se ho una colonna json con nome campo, come faccio ad aggiungere il campo cognome a questa colonna
Bionix1441

Dovrebbe essere chiaro:UPDATE users SET profile = profile || '{"lastname":"Washington"}' WHERE profile->>'name' = 'George Washington';
Fandi Susanto,

9

Per basarsi sulle risposte di @ pozs, ecco alcune altre funzioni PostgreSQL che potrebbero essere utili ad alcuni. (Richiede PostgreSQL 9.3+)

Elimina per chiave: elimina un valore dalla struttura JSON per chiave.

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

Elimina ricorsivo per chiave: elimina un valore dalla struttura JSON per percorso chiave. (richiede la json_object_set_keyfunzione di @ pozs )

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

Esempi di utilizzo:

s1=# SELECT json_object_del_key ('{"hello":[7,3,1],"foo":{"mofu":"fuwa", "moe":"kyun"}}',
                                 'foo'),
            json_object_del_path('{"hello":[7,3,1],"foo":{"mofu":"fuwa", "moe":"kyun"}}',
                                 '{"foo","moe"}');

 json_object_del_key |          json_object_del_path
---------------------+-----------------------------------------
 {"hello":[7,3,1]}   | {"hello":[7,3,1],"foo":{"mofu":"fuwa"}}

Molto utile! Grazie.
1111161171159459134,

9
UPDATE test
SET data = data::jsonb - 'a' || '{"a":5}'::jsonb
WHERE data->>'b' = '2'

Questo sembra funzionare su PostgreSQL 9.5


Funziona per me, per quanto ho capito, questo rimuove il campo "a" dai dati e quindi aggiunge il campo "a" con il nuovo valore. Nel mio caso, il valore di "a" era basato su una colonna. UPDATE test SET data = data :: jsonb - 'a' || ('{"a": "' || myColumn || '"}') :: jsonb;
sebge2,

7

Se il tipo di campo è di tipo json, funzionerà per te.

UPDATE 
table_name
SET field_name = field_name::jsonb - 'key' || '{"key":new_val}' 
WHERE field_name->>'key' = 'old_value'.

Operatore '-' cancella la coppia chiave / valore o l'elemento stringa dall'operando di sinistra. Le coppie chiave / valore sono abbinate in base al loro valore chiave.

Operatore "||" concatena due valori jsonb in un nuovo valore jsonb.

Poiché questi sono operatori jsonb, devi solo digitare typecast in :: jsonb

Ulteriori informazioni: Funzioni e operatori JSON

Puoi leggere la mia nota qui


Modo semplice e migliore per aggiornare i campi JSON, se non sei preoccupato per i riorganizzazioni dell'ordine di proprietà.
Karthik Sivaraj,

4

Con PostgreSQL 9.4, abbiamo implementato la seguente funzione python. Potrebbe funzionare anche con PostgreSQL 9.3.

create language plpython2u;

create or replace function json_set(jdata jsonb, jpaths jsonb, jvalue jsonb) returns jsonb as $$
import json

a = json.loads(jdata)
b = json.loads(jpaths)

if a.__class__.__name__ != 'dict' and a.__class__.__name__ != 'list':
  raise plpy.Error("The json data must be an object or a string.")

if b.__class__.__name__ != 'list':
   raise plpy.Error("The json path must be an array of paths to traverse.")

c = a
for i in range(0, len(b)):
  p = b[i]
  plpy.notice('p == ' + str(p))

  if i == len(b) - 1:
    c[p] = json.loads(jvalue)

  else:
    if p.__class__.__name__ == 'unicode':
      plpy.notice("Traversing '" + p + "'")
      if c.__class__.__name__ != 'dict':
        raise plpy.Error("  The value here is not a dictionary.")
      else:
        c = c[p]

    if p.__class__.__name__ == 'int':
      plpy.notice("Traversing " + str(p))
      if c.__class__.__name__ != 'list':
        raise plpy.Error("  The value here is not a list.")
      else:
        c = c[p]

    if c is None:
      break    

return json.dumps(a)
$$ language plpython2u ;

Esempio di utilizzo:

create table jsonb_table (jsonb_column jsonb);
insert into jsonb_table values
('{"cars":["Jaguar", {"type":"Unknown","partsList":[12, 34, 56]}, "Atom"]}');

select jsonb_column->'cars'->1->'partsList'->2, jsonb_column from jsonb_table;

update jsonb_table
set jsonb_column = json_set(jsonb_column, '["cars",1,"partsList",2]', '99');

select jsonb_column->'cars'->1->'partsList'->2, jsonb_column from jsonb_table;

Si noti che per un precedente datore di lavoro, ho scritto una serie di funzioni C per manipolare i dati JSON come testo (non come jsono jsonbtipo) per PostgreSQL 7, 8 e 9. Ad esempio, estrarre dati con json_path('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']'), impostare dati con json_path_set('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']', '99.87')e così via. Ci sono voluti circa 3 giorni di lavoro, quindi se ne hai bisogno per funzionare su sistemi legacy e hai tempo da perdere, potrebbe valere la pena. Immagino che la versione C sia molto più veloce della versione Python.


2

Anche se quanto segue non soddisfa questa richiesta (la funzione json_object_agg non è disponibile in PostgreSQL 9.3), può essere utile per chiunque cerchi un || operatore per PostgreSQL 9.4, come implementato nel prossimo PostgreSQL 9.5:

CREATE OR REPLACE FUNCTION jsonb_merge(left JSONB, right JSONB)
RETURNS JSONB
AS $$
SELECT
  CASE WHEN jsonb_typeof($1) = 'object' AND jsonb_typeof($2) = 'object' THEN
       (SELECT json_object_agg(COALESCE(o.key, n.key), CASE WHEN n.key IS NOT NULL THEN n.value ELSE o.value END)::jsonb
        FROM jsonb_each($1) o
        FULL JOIN jsonb_each($2) n ON (n.key = o.key))
   ELSE 
     (CASE WHEN jsonb_typeof($1) = 'array' THEN LEFT($1::text, -1) ELSE '['||$1::text END ||', '||
      CASE WHEN jsonb_typeof($2) = 'array' THEN RIGHT($2::text, -1) ELSE $2::text||']' END)::jsonb
   END     
$$ LANGUAGE sql IMMUTABLE STRICT;
GRANT EXECUTE ON FUNCTION jsonb_merge(jsonb, jsonb) TO public;
CREATE OPERATOR || ( LEFTARG = jsonb, RIGHTARG = jsonb, PROCEDURE = jsonb_merge );

2

Ho scritto una piccola funzione per me che funziona in modo ricorsivo in Postgres 9.4. Ecco la funzione (spero che funzioni bene per te):

CREATE OR REPLACE FUNCTION jsonb_update(val1 JSONB,val2 JSONB)
RETURNS JSONB AS $$
DECLARE
    result JSONB;
    v RECORD;
BEGIN
    IF jsonb_typeof(val2) = 'null'
    THEN 
        RETURN val1;
    END IF;

    result = val1;

    FOR v IN SELECT key, value FROM jsonb_each(val2) LOOP

        IF jsonb_typeof(val2->v.key) = 'object'
            THEN
                result = result || jsonb_build_object(v.key, jsonb_update(val1->v.key, val2->v.key));
            ELSE
                result = result || jsonb_build_object(v.key, v.value);
        END IF;
    END LOOP;

    RETURN result;
END;
$$ LANGUAGE plpgsql;

Ecco un esempio di utilizzo:

select jsonb_update('{"a":{"b":{"c":{"d":5,"dd":6},"cc":1}},"aaa":5}'::jsonb, '{"a":{"b":{"c":{"d":15}}},"aa":9}'::jsonb);
                            jsonb_update                             
---------------------------------------------------------------------
 {"a": {"b": {"c": {"d": 15, "dd": 6}, "cc": 1}}, "aa": 9, "aaa": 5}
(1 row)

Come puoi vedere, analizza in profondità e aggiorna / aggiungi valori dove necessario.


2

Questo ha funzionato per me, quando ho provato ad aggiornare un campo di tipo stringa.

UPDATE table_name 
SET body = jsonb_set(body, '{some_key}', to_json('value'::TEXT)::jsonb);

Spero che aiuti qualcun altro!

Supponendo che la tabella table_name abbia una colonna jsonb denominata body e si desidera modificare body.some_key = 'value'


sfortunatamente questo riformatta JSON allo stesso modo delle manipolazioni attraverso le funzioni specifiche di JSON
Lu55

1

Purtroppo, non ho trovato nulla nella documentazione, ma è possibile utilizzare una soluzione alternativa, ad esempio è possibile scrivere alcune funzioni estese.

Ad esempio, in Python:

CREATE or REPLACE FUNCTION json_update(data json, key text, value json)
returns json
as $$
from json import loads, dumps
if key is None: return data
js = loads(data)
js[key] = value
return dumps(js)
$$ language plpython3u

e poi

update test set data=json_update(data, 'a', to_json(5)) where data->>'b' = '2';

È un peccato che Amazon RDS non supporti plpython3u!
dbau,

2
Il valuerichiede inoltre una loadsquando si impostano valori non numerici come stringhe ( js[key] = loads(value)) - In caso contrario:select json_update('{"a":"a"}', 'a', to_json('b')); -> {"a": "\"b\""}
hooblei

Questa risposta potrebbe anche essere modificata per includere la cancellazione di una chiave quando il valore è impostato su Nessuno: `se il valore è Nessuno: del data [chiave]
Joshua Burns

1

Il seguente frammento di plpython potrebbe tornare utile.

CREATE EXTENSION IF NOT EXISTS plpythonu;
CREATE LANGUAGE plpythonu;

CREATE OR REPLACE FUNCTION json_update(data json, key text, value text)
 RETURNS json
 AS $$
    import json
    json_data = json.loads(data)
    json_data[key] = value
    return json.dumps(json_data, indent=4)
 $$ LANGUAGE plpythonu;

-- Check how JSON looks before updating

SELECT json_update(content::json, 'CFRDiagnosis.mod_nbs', '1')
FROM sc_server_centre_document WHERE record_id = 35 AND template = 'CFRDiagnosis';

-- Once satisfied update JSON inplace

UPDATE sc_server_centre_document SET content = json_update(content::json, 'CFRDiagnosis.mod_nbs', '1')
WHERE record_id = 35 AND template = 'CFRDiagnosis';

1

Ho trovato le risposte precedenti adatte agli utenti PostgreSQL esperti, quindi la mia risposta:

Supponiamo di avere una colonna-tabella di tipo JSONB con il seguente valore:

{
    "key0": {
        "key01": "2018-05-06T12:36:11.916761+00:00",
        "key02": "DEFAULT_WEB_CONFIGURATION",

    "key1": {
        "key11": "Data System",
        "key12": "<p>Health,<p>my address<p>USA",
        "key13": "*Please refer to main screen labeling"
    }
}

supponiamo di voler impostare un nuovo valore nella riga:

"key13": "*Please refer to main screen labeling"

e invece posizionare il valore:

"key13": "See main screen labeling"

usiamo la funzione json_set () per assegnare un nuovo valore al key13

i parametri di jsonb_set ()

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

in " target " - Inserirò il nome-colonna jsonb (questa è la colonna della tabella che viene modificata)

" path " - è il "percorso delle chiavi json" che porta (e include) la chiave che sovrascriveremo

" new_value " - questo è il nuovo valore che assegniamo

nel nostro caso vogliamo aggiornare il valore di key13 che risiede in key1 (key1 -> key13):

quindi la sintassi del percorso è: '{key1, key13}' (Il percorso era la parte più difficile da decifrare - perché i tutorial sono terribili)

jsonb_set(jsonb_column,'{key1,key13}','"See main screen labeling"')

0

Puoi anche incrementare atomicamente le chiavi in jsonbquesto modo:

UPDATE users SET counters = counters || CONCAT('{"bar":', COALESCE(counters->>'bar','0')::int + 1, '}')::jsonb WHERE id = 1;

SELECT * FROM users;

 id |    counters
----+------------
  1 | {"bar": 1}

Chiave non definita -> assume il valore iniziale di 0.

Per una spiegazione più dettagliata, vedere la mia risposta qui: https://stackoverflow.com/a/39076637


0

Per coloro che usano mybatis, ecco una dichiarazione di aggiornamento di esempio:

<update id="saveAnswer">
    update quiz_execution set answer_data = jsonb_set(answer_data, concat('{', #{qid}, '}')::text[], #{value}::jsonb), updated_at = #{updatedAt}
    where id = #{id}
</update>


Parametri:

  • qid, la chiave per il campo.
  • value, è una stringa json valida, per il valore del campo,
    ad es. convertita da oggetto in stringa json tramite jackson,

0

Ad esempio, la mia stringa è simile alla seguente: {"a1": {"a11": "x", "a22": "y", "a33": "z"}}

Aggiornamento jsons usando la tabella temporanea, che è abbastanza buona per una quantità piuttosto piccola di dati (<1.000.000). Ho trovato un modo diverso, ma poi sono andato in vacanza e l'ho dimenticato ...

Così. la query sarà simile a questa:

with temp_table as (
select 
a.id,
a->'a1'->>'a11' as 'a11',
a->'a1'->>'a22' as 'a22',
a->'a1'->>'a33' as 'a33',
u1.a11updated
from foo a
join table_with_updates u1 on u1.id = a.id)
    update foo a
    set a = ('{"a1": {"a11": "'|| t.a11updated ||'",
        "a22":"'|| t.a22 ||'",
        "a33":"'|| t.a33 ||'"}}')::jsonb
    from temp_table t
    where t.id = a.id;

Ha più a che fare con la stringa che con JSON, ma funziona. Fondamentalmente, estrae tutti i dati nella tabella temporanea, crea una stringa mentre collega i fori concat con i dati di cui è stato eseguito il backup e li converte in jsonb.

Json_set potrebbe essere più efficiente, ma sto ancora cercando di capire. La prima volta che ho provato a usarlo, ho incasinato completamente la stringa ...


1
ciao e benvenuto su StackOverflow! Si noti che esiste già una risposta accettata a questa domanda.
hongsy,

-2

Se si sta eseguendo questa query con un client del linguaggio di programmazione, ad esempio da python pycopg2, o Node Postgres, accertarsi di analizzare prima i nuovi dati su JSON.

Potrebbe facilmente sembrare che un dizionario Python sia uguale a un oggetto JSON ma non esegue prima json.dumps nel dizionario.

Un semplice frammento di pitone:

def change_destination(self,parcel_id,destlatlng): query="UPDATE parcels SET destlatlng = '{}' WHERE parcel_id ={};".format(json.dumps(destlatlng), parcel_id) self.cursor.execute(query2) self.connection.commit()

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.