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

Insira um novo item na coluna JSONB com base no valor de outro campo - postgres


Isso deve ser informação suficiente para completar a consulta:

Vamos criar os dados simulados
create table a (id serial primary key , b jsonb);

insert into a (b)
values ('[
  {
    "name": "test",
    "features": [
      {
        "name": "feature1",
        "granted": false
      },
      {
        "name": "feature2",
        "granted": true
      }
    ]
  },
  {
    "name": "another-name",
    "features": [
      {
        "name": "feature1",
        "granted": false
      },
      {
        "name": "feature2",
        "granted": true
      }
    ]
  }
]');

Agora exploda a matriz usando jsonb_array_elements com ordinalidade para obter o índice e a propriedade
select first_level.id, position, feature_position, feature
from (select a.id, arr.*
      from a,
           jsonb_array_elements(a.b) with ordinality arr (elem, position)
      where elem ->> 'name' = 'test') first_level,
     jsonb_array_elements(first_level.elem -> 'features') with ordinality features (feature, feature_position);

O resultado desta consulta é:
1,1,1,"{""name"": ""feature1"", ""granted"": false}"
1,1,2,"{""name"": ""feature2"", ""granted"": true}"

Lá você tem as informações necessárias para buscar os subelementos necessários, bem como todos os índices necessários para sua consulta.

Agora, para a edição final, você já tinha a consulta que queria:
UPDATE my_table SET modules =
    jsonb_insert(my_column, '{0, features, 0}', '{"name": "newFeature", "granted": false}')
WHERE my_column ->> 'name' = 'test' AND my_column @> '{"features": [{"name":"feature1", "granted": false}]}';

No where você usará o id, porque essas são as linhas nas quais você está interessado e nos índices que você obteve da consulta. Então:
UPDATE my_table SET modules =
    jsonb_insert(my_column, '{' || exploded_info.position::string || ', features, ' || exploded_info.feature_position || '}', '{"name": "newFeature", "granted": false}') from (/* previous query */) as exploded_info
WHERE exploded_info.id = my_table.id and exploded_info.feature -> 'granted' = false;

Como você pode ver isso facilmente fica muito desagradável.

Eu recomendaria usar uma abordagem mais sql, ou seja, ter recursos em uma tabela em vez de dentro de um json, um fk ligando isso à sua tabela...Se você realmente precisar usar o json, por exemplo, porque o domínio é realmente complexo e definido no nível do aplicativo e muito flexível. Então eu recomendaria fazer as atualizações dentro do código do aplicativo