PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Insérer un nouvel élément dans la colonne JSONB en fonction de la valeur d'un autre champ - postgres

Cela devrait être suffisant pour compléter la requête :

Créons les données fictives

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

Décomposez maintenant le tableau en utilisant jsonb_array_elements avec l'ordinalité pour obtenir l'index et la propriété

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

Le résultat de cette requête est :

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

Vous y trouverez les informations nécessaires pour récupérer les sous-éléments dont vous avez besoin, ainsi que tous les index dont vous avez besoin pour votre requête.

Maintenant, pour la dernière modification, vous aviez déjà la requête que vous vouliez :

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

Dans le où vous utiliserez l'identifiant, car ce sont les lignes qui vous intéressent, et dans les index, vous les avez obtenus à partir de la requête. Donc :

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;

Comme vous pouvez le voir, cela devient facilement très désagréable.

Je recommanderais soit d'utiliser une approche plus sql, c'est-à-dire d'avoir des fonctionnalités dans une table au lieu d'un json, un fk reliant cela à votre table... Si vous avez vraiment besoin d'utiliser le json, par exemple, parce que le domaine est vraiment complexe et défini au niveau de l'application et très flexible. Ensuite, je recommanderais de faire les mises à jour dans le code de l'application