Atualização : Com o PostgreSQL 9.5 , existem algumas jsonb
funcionalidades de manipulação no próprio PostgreSQL (mas nenhuma para json
; as conversões são necessárias para manipular json
valores).
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)
path
també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 path
contagem 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 path
in 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.
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"
UPSERT
, não umUPDATE
. Se a chave ainda não existir no campo json, ela será adicionada. Olhe para essa pergunta relacionada para o realUPDATE
: stackoverflow.com/questions/7711432/... (Isto é para um tipo composto, mas o principal é semelhante para JSON.)$2::text
.Com a versão 9.5, use jsonb_set-
onde body é um tipo de coluna jsonb.
fonte
upper
assim: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? thxCom o Postgresql 9.5, isso pode ser feito seguindo-se:
OU
Alguém perguntou como atualizar muitos campos no valor jsonb de uma só vez. Suponha que criamos uma tabela:
Em seguida, inserimos uma linha experimental:
ATUALIZAMOS a linha:
O que faz o seguinte:
Selecionando os dados:
Vai resultar em:
Para atualizar o campo, não use o operador concat
||
. Use jsonb_set. O que não é simples:Usando o operador concat para {c, c1}, por exemplo:
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, najsonb_set
função e também najsonb_insert
função.fonte
UPDATE users SET profile = profile || '{"lastname":"Washington"}' WHERE profile->>'name' = 'George Washington';
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.
Exclusão recursiva por chave: exclui um valor da estrutura JSON pelo caminho da chave. (requer a
json_object_set_key
função de @ pozs )Exemplos de uso:
fonte
Isso parece estar funcionando no PostgreSQL 9.5
fonte
Se o seu tipo de campo for json, o seguinte funcionará para você.
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
fonte
Com o PostgreSQL 9.4, implementamos a seguinte função python. Também pode funcionar com o PostgreSQL 9.3.
Exemplo de uso:
Observe que para um empregador anterior, escrevi um conjunto de funções C para manipular dados JSON como texto (não como
json
oujsonb
tipo) para o PostgreSQL 7, 8 e 9. Por exemplo, extrair dados comjson_path('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']')
, definir dados comjson_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.fonte
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:
fonte
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ê):
Aqui está o uso da amostra:
Como você pode ver, analise no fundo e atualize / adicione valores sempre que necessário.
fonte
Isso funcionou para mim, ao tentar atualizar um campo do tipo string.
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'
fonte
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:
e depois
fonte
value
também vai exigir umloads
ao 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\""}
O seguinte trecho plpython pode ser útil.
fonte
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:
vamos assumir que queremos definir um novo valor na linha:
e, em vez disso, coloque o valor:
usamos a função json_set () para atribuir um novo valor à key13
os parâmetros para jsonb_set ()
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)
fonte
Você também pode incrementar chaves atomicamente dentro
jsonb
desta maneira:Chave indefinida -> assume o valor inicial de 0.
Para uma explicação mais detalhada, consulte minha resposta aqui: https://stackoverflow.com/a/39076637
fonte
Para quem usa
mybatis
, aqui está um exemplo de instrução de atualização: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
,fonte
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:
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 ...
fonte
Se você estiver fazendo essa consulta com um cliente de linguagem de programação, por exemplo
python pycopg2
, from , ouNode 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()
fonte