¿Cómo modifico los campos dentro del nuevo tipo de datos PostgreSQL JSON?

235

Con postgresql 9.3 puedo SELECCIONAR campos específicos de un tipo de datos JSON, pero ¿cómo los modifica usando ACTUALIZAR? No puedo encontrar ningún ejemplo de esto en la documentación de postgresql, o en cualquier lugar en línea. He intentado lo obvio:

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...
usuario9645
fuente

Respuestas:

331

Actualización : con PostgreSQL 9.5 , hay algunas jsonbfunciones de manipulación dentro de PostgreSQL (pero ninguna para json; se requieren conversiones para manipular los jsonvalores).

Fusionar 2 (o más) objetos JSON (o concatenar matrices):

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

Por lo tanto, configurar una tecla simple se puede hacer usando:

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

Donde <key>debe ser una cadena, y <value>puede ser cualquier tipo que to_jsonb()acepte.

Para establecer un valor profundo en una jerarquía JSON , jsonb_set()se puede usar la función:

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

Lista completa de parámetros de jsonb_set():

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

pathtambién puede contener índices de matriz JSON y los enteros negativos que aparecen allí cuentan desde el final de las matrices JSON. Sin embargo, un índice de matriz JSON no existente pero positivo agregará el elemento al final de la matriz:

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

Para insertar en la matriz JSON (mientras se conservan todos los valores originales) , jsonb_insert()se puede usar la función ( en 9.6+; esta función solo, en esta sección ):

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

Lista completa de parámetros de jsonb_insert():

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

De nuevo, los enteros negativos que aparecen en el pathrecuento desde el final de las matrices JSON.

Entonces, f.ex. agregar al final de una matriz JSON se puede hacer 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

Sin embargo, esta función funciona de manera ligeramente diferente (que jsonb_set()) cuando pathin targetes la clave de un objeto JSON. En ese caso, solo agregará un nuevo par clave-valor para el objeto JSON cuando no se use la clave. Si se usa, generará un error:

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

La eliminación de una clave (o un índice) de un objeto JSON (o de una matriz) se puede hacer con el -operador:

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

La eliminación, desde lo profundo de una jerarquía JSON, se puede hacer con el #-operador:

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

Para 9.4 , puede usar una versión modificada de la respuesta original (a continuación), pero en lugar de agregar una cadena JSON, puede agregarla directamente a un objeto json json_object_agg().

Respuesta original : es posible (sin plpython o plv8) en SQL puro también (pero necesita 9.3+, no funcionará 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

Editar :

Una versión, que establece múltiples claves y valores:

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

Edición 2 : como señaló @ErwinBrandstetter , estas funciones anteriores funcionan como un llamado UPSERT(actualiza un campo si existe, lo inserta si no existe). Aquí hay una variante, que 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$;

Edición 3 : Aquí hay una variante recursiva, que puede establecer ( UPSERT) un valor de hoja (y usa la primera función de esta respuesta), ubicada en una ruta de clave (donde las claves solo pueden referirse a objetos internos, no se admiten matrices internas):

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

Actualización : las funciones están compactadas ahora.

pozs
fuente
55
Probé su función plpgsql, pero no estoy seguro de cómo usarla. Veo un error cuando intento select json_object_set_key((select data from test where data->>'b' = '2'), 'b', 'two'); un mensaje de error ERROR: could not determine polymorphic type because input has type "unknown"
user9645
1
Esto realiza el equivalente de un UPSERT, no un UPDATE. Si la clave aún no existe en el campo json, se agrega. Mire a esta pregunta relacionada para un real UPDATE: stackoverflow.com/questions/7711432/… (Esto es para un tipo compuesto, pero el principal es similar para json.)
Erwin Brandstetter
1
@ErwinBrandstetter eso es cierto, pero en json un UPSERT generalmente es más general que una modificación de tipo ACTUALIZACIÓN (considere f.ex. sqlfiddle.com/#!15/d41d8/2897 ) - Interpreté la pregunta original como cómo se modifica ellos (columnas json) usando una instrucción UPDATE? - además de una sola condición podría transformar esto a ACTUALIZAR.
Pozs
1
Muy útil y completo ahora.
Erwin Brandstetter
1
@maxhud que depende del cliente (o la biblioteca del cliente que use). Si puede, use tipos explícitos (PostgreSQL puede adivinar tipos en consultas parametrizadas, pero eso generalmente no funciona bien con funciones polimórficas). Pero al menos, puedes usar lanzamientos explícitos, como $2::text.
pozs
98

Con 9.5 use jsonb_set-

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

donde body es un tipo de columna jsonb.

Teo Choong Ping
fuente
Hola, ¿por qué no puedo usar upperasí: update objects set body=jsonb_set(body, '{name}', upper('"Mary"'), true) where id=1;no reconoce, o cómo puedo lograr el mismo comportamiento? thx
Rafael Capucho
1
Si el valor que quiero establecer es una subcadena de otra columna en lugar de "Mary", ¿cómo lo haría?
Andrew
58

Con Postgresql 9.5 se puede hacer siguiendo:

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

O

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

Alguien preguntó cómo actualizar muchos campos en el valor jsonb a la vez. Supongamos que creamos una tabla:

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

Luego INSERTAMOS una fila experimental:

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

Luego ACTUALIZAMOS la fila:

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

Que hace lo siguiente:

  1. Actualiza el campo a
  2. Elimina el campo b.
  3. Agrega el campo d

Seleccionar los datos:

SELECT jsonb_pretty(object) FROM testjsonb;

Resultará en:

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

Para actualizar el campo dentro, no use el operador concat ||. Use jsonb_set en su lugar. Lo cual no es simple:

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

Usando el operador concat para {c, c1} por ejemplo:

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

Eliminará {c, c2} y {c, c3}.

Para obtener más potencia, busque potencia en la documentación de funciones jgres de postgresql . Uno podría estar interesado en el #-operador, la jsonb_setfunción y también la jsonb_insertfunción.

Fandi Susanto
fuente
y si tengo que actualizar dos campos, ¿cuál es la sintaxis?
Sunil Garg
si tengo una columna json con el nombre del campo, ¿cómo agrego el campo de apellido a esta columna
Bionix1441
Debe quedar claro:UPDATE users SET profile = profile || '{"lastname":"Washington"}' WHERE profile->>'name' = 'George Washington';
Fandi Susanto
9

Para construir sobre las respuestas de @ pozs, aquí hay un par de funciones más de PostgreSQL que pueden ser útiles para algunos. (Requiere PostgreSQL 9.3+)

Eliminar por clave: elimina un valor de la estructura JSON por clave.

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

Eliminar recursivo por clave: elimina un valor de la estructura JSON por la ruta de la clave. (requiere la json_object_set_keyfunción de @ 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$;

Ejemplos de uso:

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"}}
shru
fuente
¡Muy útil! Gracias.
1111161171159459134
9
UPDATE test
SET data = data::jsonb - 'a' || '{"a":5}'::jsonb
WHERE data->>'b' = '2'

Esto parece estar funcionando en PostgreSQL 9.5

sigod
fuente
Funciona para mí, por lo que he entendido, esto elimina el campo "a" de los datos y luego agrega el campo "a" con el nuevo valor. En mi caso, el valor de "a" se basó en una columna. ACTUALIZAR prueba SET data = data :: jsonb - 'a' || ('{"a": "' || myColumn || '"}') :: jsonb;
sebge2
7

Si su tipo de campo es json, lo siguiente funcionará para usted.

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

El operador '-' elimina el par clave / valor o el elemento de cadena del operando izquierdo. Los pares clave / valor se corresponden en función de su valor clave.

Operador '||' concatena dos valores jsonb en un nuevo valor jsonb.

Dado que estos son operadores jsonb, solo necesita escribir a :: jsonb

Más información: Funciones y operadores JSON

Puedes leer mi nota aquí

Neethu
fuente
Una manera simple y mejor de actualizar los campos JSON, si no le preocupan los reordenamientos del orden de propiedad.
Karthik Sivaraj
4

Con PostgreSQL 9.4, hemos implementado la siguiente función de Python. También puede funcionar 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 ;

Ejemplo de uso:

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;

Tenga en cuenta que para un empleador anterior, he escrito un conjunto de funciones C para manipular datos JSON como texto (no como un jsono jsonbtipo) para PostgreSQL 7, 8 y 9. Por ejemplo, extraer datos con json_path('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']'), establecer datos con, json_path_set('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']', '99.87')etc. Tomó alrededor de 3 días de trabajo, por lo que si necesita que se ejecute en sistemas heredados y tenga tiempo de sobra, puede valer la pena el esfuerzo. Me imagino que la versión C es mucho más rápida que la versión python.

Magnus
fuente
2

Aunque lo siguiente no satisfará esta solicitud (la función json_object_agg no está disponible en PostgreSQL 9.3), lo siguiente puede ser útil para cualquiera que busque un || operador para PostgreSQL 9.4, tal como se implementará en el próximo 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 );
Ziggy Crueltyfree Zeitgeister
fuente
2

Escribí una pequeña función para mí que funciona de forma recursiva en Postgres 9.4. Aquí está la función (espero que funcione bien para usted):

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;

Aquí está el uso de muestra:

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)

Como puede ver, analice en profundidad y actualice / agregue valores donde sea necesario.

J. Raczkiewicz
fuente
2

Esto funcionó para mí, cuando intentaba actualizar un campo de tipo cadena.

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

¡Espero que ayude a alguien más!

Suponiendo que la tabla nombre_tabla tiene una columna jsonb llamada cuerpo y desea cambiar body.some_key = 'value'

Antonio
fuente
desafortunadamente esto formatea JSON de la misma manera que las manipulaciones a través de las funciones específicas de JSON
Lu55
1

Lamentablemente, no he encontrado nada en la documentación, pero puede usar alguna solución alternativa, por ejemplo, podría escribir alguna función extendida.

Por ejemplo, en 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

y entonces

update test set data=json_update(data, 'a', to_json(5)) where data->>'b' = '2';
Roman Pekar
fuente
Es una pena que Amazon RDS no sea compatible con plpython3u.
dbau
2
El valuetambién requerirá una loadshora de establecer valores no numéricos (como cuerdas js[key] = loads(value)) - De lo contrario:select json_update('{"a":"a"}', 'a', to_json('b')); -> {"a": "\"b\""}
hooblei
Esta respuesta también podría modificarse para incluir la eliminación de una clave cuando el valor se establece en Ninguno: `si el valor es Ninguno: del dato [clave]
Joshua Burns
1

El siguiente fragmento de plpython puede ser útil.

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';
Sandeep
fuente
1

Encontré que las respuestas anteriores son usuarios de PostgreSQL experimentados adecuados, de ahí mi respuesta:

Suponga que tiene una tabla-columna de tipo JSONB con el siguiente valor:

{
    "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"
    }
}

supongamos que queremos establecer un nuevo valor en la fila:

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

y en su lugar coloque el valor:

"key13": "See main screen labeling"

Usamos la función json_set () para asignar un nuevo valor a la clave13

los parámetros para jsonb_set ()

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

en " target ": colocaré el nombre de columna jsonb (esta es la columna de la tabla que se está modificando)

" ruta ": es la "ruta de teclas json" que conduce a (e incluye) la clave que vamos a sobrescribir

" new_value ": este es el nuevo valor que asignamos

en nuestro caso, queremos actualizar el valor de key13 que reside en key1 (key1 -> key13):

por lo tanto, la sintaxis de la ruta es: '{key1, key13}' (La ruta fue la parte más difícil de descifrar, porque los tutoriales son terribles)

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

También puede incrementar las claves atómicamente dentro de jsonbesta manera:

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}

Clave indefinida -> asume el valor inicial de 0.

Para una explicación más detallada, vea mi respuesta aquí: https://stackoverflow.com/a/39076637

joonas.fi
fuente
0

Para aquellos que usan mybatis, aquí hay una declaración de actualización de ejemplo:

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


Parámetros:

  • qid, la clave para el campo.
  • value, es una cadena json válida, para el valor de campo,
    por ejemplo , convertida de objeto a cadena json a través de jackson,
Eric Wang
fuente
0

Entonces, por ejemplo, mi cadena se ve así: {"a1": {"a11": "x", "a22": "y", "a33": "z"}}

Actualizo jsons usando la tabla temporal, que es lo suficientemente buena para una cantidad de datos bastante pequeña (<1.000.000). Encontré una forma diferente, pero luego me fui de vacaciones y lo olvidé ...

Entonces. la consulta será algo como esto:

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;

Tiene más que ver con cadenas que con json, pero funciona. Básicamente, extrae todos los datos en la tabla temporal, crea una cadena mientras conecta los agujeros de concat con los datos de los que realizó una copia de seguridad y los convierte en jsonb.

Json_set podría ser más eficiente, pero todavía me estoy acostumbrando. La primera vez que intenté usarlo, estropeé la cadena por completo ...

Vlad S
fuente
1
hola y bienvenidos a StackOverflow! Tenga en cuenta que ya hay una respuesta aceptada a esta pregunta.
hongsy
-2

Si está realizando esta consulta con un cliente de lenguaje de programación, por ejemplo python pycopg2, desde o Node Postgres, asegúrese de analizar primero los datos nuevos a JSON.

Puede parecer fácilmente que un diccionario de Python es lo mismo que un objeto JSON, pero no hace primero json.dumps en el diccionario.

Un simple fragmento de python:

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()

Cryce Truly
fuente