PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

UPDATE com jsonb_set() afeta apenas um objeto na matriz aninhada

Explicação


A subseleção no FROM cláusula do seu UPDATE retorna três linhas. Mas cada linha na tabela de destino só pode ser atualizada uma vez em um único UPDATE comando. O resultado é que você só vê o efeito de um dessas três linhas.

Ou, nas palavras do manual :

A parte:não chame sua subconsulta de "cte". Não é uma Expressão de tabela comum .

UPDATE adequada

UPDATE table_ t
SET    value_ = jsonb_set(value_, '{iProps}', sub2.new_prop, false)
FROM  (
   SELECT id
        , jsonb_agg(jsonb_set(prop, '{value, rules}', new_rules, false)
                    ORDER BY idx1) AS new_prop
   FROM  (
      SELECT t.id, arr1.prop, arr1.idx1
           , jsonb_agg(jsonb_set(rule, '{ao,sc}', rule #> '{ao,sc,name}', false)
                       ORDER BY idx2) AS new_rules
      FROM table_ t
         , jsonb_array_elements(value_->'iProps')       WITH ORDINALITY arr1(prop,idx1)
         , jsonb_array_elements(prop->'value'->'rules') WITH ORDINALITY arr2(rule,idx2)
      GROUP  BY t.id, arr1.prop, arr1.idx1
      ) sub1
   GROUP  BY id
   ) sub2
WHERE t.id = sub2.id;

db<>fiddle aqui

Use jsonb_set() em cada objeto (elemento de array) antes de agregá-los de volta em um array. Primeiro no nível da folha, e novamente no nível mais profundo.

Eu adicionei id como PRIMARY KEY para a mesa. Precisamos de alguma coluna exclusiva para manter as linhas separadas.

O ORDER BY adicionado pode ou não ser necessária. Adicionado para garantir o pedido original.

Obviamente, se seus dados forem tão regulares quanto a amostra, um design relacional com colunas dedicadas pode ser uma alternativa mais simples. Ver