Como modificar campos dentro do novo tipo de dados JSON do PostgreSQL?


235

Com o postgresql 9.3, posso SELECIONAR campos específicos de um tipo de dados JSON, mas como você os modifica usando UPDATE? Não consigo encontrar nenhum exemplo disso na documentação do postgresql ou em qualquer lugar online. Eu tentei o óbvio:

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

Respostas:


331

Atualização : Com o PostgreSQL 9.5 , existem algumas jsonbfuncionalidades de manipulação no próprio PostgreSQL (mas nenhuma para json; as conversões são necessárias para manipular jsonvalores).

Mesclando 2 (ou mais) objetos JSON (ou concatenando matrizes):

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

Portanto, a configuração de uma chave simples pode ser feita usando:

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

Onde <key>deve ser uma string e <value>pode ser qualquer tipo que seja to_jsonb()aceito.

Para definir um valor profundo em uma hierarquia JSON , a jsonb_set()função pode ser usada:

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)

pathtambém pode conter índices de matriz JSON e números inteiros negativos que aparecem lá são contados a partir do final de matrizes JSON. No entanto, um índice de matriz JSON positivo, mas não existente, acrescentará o elemento ao final da 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 inserir na matriz JSON (preservando todos os valores originais) , a jsonb_insert()função pode ser usada ( em 9.6+; somente nesta função, nesta seção ):

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)

Novamente, números inteiros negativos que aparecem na pathcontagem do final das matrizes JSON.

Então, f.ex. anexar ao final de uma matriz JSON pode ser feito com:

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

No entanto, essa função está funcionando de maneira ligeiramente diferente (que jsonb_set()) quando pathin targeté a chave de um objeto JSON. Nesse caso, ele incluirá apenas um novo par de valores-chave para o objeto JSON quando a chave não for usada. Se for usado, ocorrerá um erro:

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

A exclusão de uma chave (ou de um índice) de um objeto JSON (ou de uma matriz) pode ser feita com o -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]'

A exclusão de uma hierarquia JSON profunda pode ser feita com o #-operador:

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

Para a 9.4 , é possível usar uma versão modificada da resposta original (abaixo), mas, em vez de agregar uma sequência JSON, é possível agregar diretamente em um objeto json json_object_agg().

Resposta original : É possível (sem plpython ou plv8) também em SQL puro (mas precisa de 9.3+, não funcionará com 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 :

Uma versão que define várias chaves e 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$;

Editar 2 : como o @ErwinBrandstetter observou que essas funções acima funcionam como as chamadas UPSERT(atualiza um campo, se existir, insere, se não existir). Aqui está uma variante, que apenas 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$;

Edit 3 : Aqui está uma variante recursiva, que pode definir ( UPSERT) um valor de folha (e usa a primeira função desta resposta), localizada em um caminho de chave (onde as chaves podem se referir apenas a objetos internos, matrizes internas não suportadas):

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

Atualização : as funções são compactadas agora.


5
Eu tentei a sua função plpgsql, mas não estou certo de como usá-lo - Estou vendo um erro quando tento select json_object_set_key((select data from test where data->>'b' = '2'), 'b', 'two'); mensagem de erro é ERROR: could not determine polymorphic type because input has type "unknown"
user9645

1
Isso executa o equivalente a um UPSERT, não um UPDATE. Se a chave ainda não existir no campo json, ela será adicionada. Olhe para essa pergunta relacionada para o real UPDATE: stackoverflow.com/questions/7711432/... (Isto é para um tipo composto, mas o principal é semelhante para JSON.)
Erwin Brandstetter

1
@ErwinBrandstetter isso é verdade, mas em json um UPSERT geralmente é mais geral do que uma modificação do tipo UPDATE (considere f.ex. sqlfiddle.com/#!15/d41d8/2897 ) - interpretei a pergunta original como você modifica eles (colunas json) usando uma instrução UPDATE? - além de uma única condição, poderia transformar isso em UPDATE.
pozs

1
Muito útil e completo agora.
Erwin Brandstetter

1
@maxhud que depende do cliente (ou da biblioteca do cliente que você usa). Se puder, use tipos explícitos (o PostgreSQL pode adivinhar tipos em consultas parametrizadas, mas isso geralmente não funciona bem com funções polimórficas). Mas pelo menos, você pode usar elencos explícitos, como $2::text.
pozs

98

Com a versão 9.5, use jsonb_set-

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

onde body é um tipo de coluna jsonb.


Olá, por que não posso usar upperassim: update objects set body=jsonb_set(body, '{name}', upper('"Mary"'), true) where id=1;ele não reconhece, ou como posso obter o mesmo comportamento? thx
Rafael Capucho

1
Se o valor que eu quero definir é uma substring de outra coluna em vez de "Mary", como eu faria isso?
18717 Andrew

58

Com o Postgresql 9.5, isso pode ser feito seguindo-se:

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

OU

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

Alguém perguntou como atualizar muitos campos no valor jsonb de uma só vez. Suponha que criamos uma tabela:

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

Em seguida, inserimos uma linha experimental:

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

ATUALIZAMOS a linha:

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

O que faz o seguinte:

  1. Atualiza o campo a
  2. Remove o campo b
  3. Adicione o campo d

Selecionando os dados:

SELECT jsonb_pretty(object) FROM testjsonb;

Vai resultar em:

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

Para atualizar o campo, não use o operador concat ||. Use jsonb_set. O que não é simples:

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

Usando o operador concat para {c, c1}, por exemplo:

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

Irá remover {c, c2} e {c, c3}.

Para obter mais poder, procure poder na documentação das funções do json do postgresql . Alguém pode estar interessado no #-operador, na jsonb_setfunção e também na jsonb_insertfunção.


e se eu tiver que atualizar dois campos, qual é a sintaxe?
Sunil Garg

se eu tiver uma coluna JSON com nome de campo, como faço para adicionar campo sobrenome para esta coluna
Bionix1441

Deve ficar claro: #UPDATE users SET profile = profile || '{"lastname":"Washington"}' WHERE profile->>'name' = 'George Washington';
Fandi Susanto

9

Para desenvolver as respostas do @ pozs, aqui estão algumas funções do PostgreSQL que podem ser úteis para alguns. (Requer PostgreSQL 9.3 ou superior)

Excluir por chave: exclui um valor da estrutura JSON por chave.

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

Exclusão recursiva por chave: exclui um valor da estrutura JSON pelo caminho da chave. (requer a json_object_set_keyfunção 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$;

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

Muito útil! Obrigado.
1111161171159459134

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

Isso parece estar funcionando no PostgreSQL 9.5


Funciona para mim, tanto quanto eu entendi, isso remove o campo "a" dos dados e, em seguida, anexa o campo "a" ao novo valor. No meu caso, o valor de "a" foi baseado em uma coluna. UPDATE test SET data = data :: jsonb - 'a' || ('{"a": "' | myColumn || '"}') :: jsonb;
sebge2

7

Se o seu tipo de campo for json, o seguinte funcionará para você.

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

Operador '-' exclui o par de chave / valor ou elemento de string do operando esquerdo. Os pares de chave / valor são correspondidos com base em seu valor de chave.

Operador '||' concatene dois valores jsonb em um novo valor jsonb.

Como esses são operadores jsonb, você só precisa digitar para :: jsonb

Mais informações: Funções e operadores JSON

Você pode ler minha nota aqui


Maneira simples e melhor de atualizar os campos JSON, se você não estiver preocupado com os rearranjos de pedidos de propriedades.
Karthik Sivaraj

4

Com o PostgreSQL 9.4, implementamos a seguinte função python. Também pode funcionar com o 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 ;

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

Observe que para um empregador anterior, escrevi um conjunto de funções C para manipular dados JSON como texto (não como jsonou jsonbtipo) para o PostgreSQL 7, 8 e 9. Por exemplo, extrair dados com json_path('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']'), definir dados com json_path_set('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']', '99.87')e assim por diante. Demorou cerca de 3 dias de trabalho; portanto, se você precisar rodar em sistemas legados e tiver tempo de sobra, pode valer a pena. Eu imagino que a versão C seja muito mais rápida que a versão python.


2

Embora o seguinte não atenda a essa solicitação (a função json_object_agg não está disponível no PostgreSQL 9.3), o seguinte pode ser útil para quem procura um || operador para PostgreSQL 9.4, conforme implementado no 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 );

2

Escrevi para mim uma pequena função que funciona recursivamente no Postgres 9.4. Aqui está a função (espero que funcione bem para você):

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;

Aqui está o uso da amostra:

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 você pode ver, analise no fundo e atualize / adicione valores sempre que necessário.


2

Isso funcionou para mim, ao tentar atualizar um campo do tipo string.

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

Espero que ajude alguém!

Supondo que a tabela nome_da_tabela tenha uma coluna jsonb denominada corpo e que você queira alterar body.some_key = 'value'


Infelizmente, este reformata JSON da mesma forma que as manipulações através das funções específicas do JSON
Lu55

1

Infelizmente, não encontrei nada na documentação, mas você pode usar alguma solução alternativa, por exemplo, pode escrever alguma função estendida.

Por exemplo, em 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 depois

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

É uma pena que o Amazon RDS não suporte o plpython3u!
dbau 23/02

2
O valuetambém vai exigir um loadsao definir valores não numéricos como strings ( js[key] = loads(value)) - Caso contrário:select json_update('{"a":"a"}', 'a', to_json('b')); -> {"a": "\"b\""}
hooblei

Essa resposta também poderia ser modificado para incluir a exclusão de uma chave quando o valor é definido como Nenhum: `se o valor é None: del dados [chave]
Joshua Burns,

1

O seguinte trecho plpython pode 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';

1

Encontrei respostas anteriores adequadas para usuários experientes do PostgreSQL, portanto, minha resposta:

Suponha que você tenha uma coluna da tabela do tipo JSONB com o seguinte 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"
    }
}

vamos assumir que queremos definir um novo valor na linha:

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

e, em vez disso, coloque o valor:

"key13": "See main screen labeling"

usamos a função json_set () para atribuir um novo valor à key13

os parâmetros para jsonb_set ()

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

em " target " - colocarei o nome da coluna jsonb (esta é a coluna da tabela que está sendo modificada)

" path " - é o "caminho das chaves do json" que leva (e inclui) a chave que vamos sobrescrever

" new_value " - este é o novo valor que atribuímos

no nosso caso, queremos atualizar o valor da chave13 que reside na chave1 (chave1 -> chave13):

portanto, a sintaxe do caminho é: '{key1, key13}' (o caminho foi a parte mais complicada de decifrar - porque os tutoriais são terríveis)

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

0

Você também pode incrementar chaves atomicamente dentro jsonbdesta maneira:

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}

Chave indefinida -> assume o valor inicial de 0.

Para uma explicação mais detalhada, consulte minha resposta aqui: https://stackoverflow.com/a/39076637


0

Para quem usa mybatis, aqui está um exemplo de instrução de atualização:

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


Params:

  • qid, a chave para o campo.
  • value, é uma string json válida, para o valor do campo,
    por exemplo , convertida de objeto em string json por meio de jackson,

0

Assim, por exemplo, minha string fica assim: {"a1": {"a11": "x", "a22": "y", "a33": "z"}}

Eu atualizo jsons usando a tabela temp, que é boa o suficiente para uma quantidade bastante pequena de dados (<1.000.000). Encontrei uma maneira diferente, mas depois fui de férias e esqueci ...

Assim. a consulta será algo como isto:

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;

Tem mais a ver com string do que json, mas funciona. Basicamente, ele puxa todos os dados para a tabela temporária, cria uma string enquanto conecta orifícios de concatenação com os dados dos quais você fez backup e os converte em jsonb.

Json_set pode ser mais eficiente, mas ainda estou pegando um jeito. A primeira vez que tentei usá-lo, estraguei completamente a corda ...


1
oi e bem-vindo ao StackOverflow! Observe que já existe uma resposta aceita para esta pergunta.
hongsy 21/01

-2

Se você estiver fazendo essa consulta com um cliente de linguagem de programação, por exemplo python pycopg2, from , ou Node Postgres, certifique-se de analisar os novos dados para JSON primeiro.

Pode parecer facilmente que um dicionário python é o mesmo que um objeto JSON, mas não executa o json.dumps no dicionário.

Um trecho simples 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()

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.