sql >> Base de Datos >  >> RDS >> PostgreSQL

Inserte un nuevo elemento en la columna JSONB según el valor de otro campo - postgres

Esta debería ser suficiente información para completar la consulta:

Vamos a crear los datos 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
      }
    ]
  }
]');

Ahora explote la matriz usando jsonb_array_elements con ordinalidad para obtener el índice y la propiedad

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

El resultado de esta consulta es:

1,1,1,"{""name"": ""feature1"", ""granted"": false}"
1,1,2,"{""name"": ""feature2"", ""granted"": true}"

Allí tiene la información necesaria que necesita para obtener los subelementos que necesita, así como todos los índices que necesita para su consulta.

Ahora, para la edición final, ya tenías la consulta que querías:

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

En donde usará la identificación, porque esas son las filas que le interesan, y en los índices que obtuvo de la consulta. Entonces:

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 puede ver, esto fácilmente se vuelve muy desagradable.

Recomendaría usar un enfoque más sql, es decir, tener características en una tabla en lugar de dentro de un json, un fk que lo vincule a su tabla... Si realmente necesita usar el json, por ejemplo, porque el dominio es realmente complejo y definido a nivel de aplicación y muy flexible. Entonces recomendaría hacer las actualizaciones dentro del código de la aplicación