PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Inserisci un nuovo elemento nella colonna JSONB in ​​base al valore dell'altro campo - postgres

Queste informazioni dovrebbero essere sufficienti per completare la query:

Creiamo i dati fittizi

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

Ora esplodi l'array usando jsonb_array_elements con ordinalità per ottenere l'indice e la proprietà

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

Il risultato di questa query è:

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

Lì hai le informazioni necessarie per recuperare i sottoelementi di cui hai bisogno, nonché tutti gli indici di cui hai bisogno per la tua query.

Ora, alla modifica finale, avevi già la query che volevi:

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

In dove utilizzerai l'id, perché quelle sono le righe che ti interessano e negli indici le hai ottenute dalla query. Quindi:

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;

Come puoi vedere, questo diventa facilmente molto brutto.

Consiglierei di utilizzare un approccio più sql, ovvero avere funzionalità in una tabella anziché all'interno di un json, un fk che lo collega alla tua tabella ... Se hai davvero bisogno di usare json, ad esempio, perché il dominio è davvero complesso e definito a livello di applicazione e molto flessibile. Quindi consiglierei di eseguire gli aggiornamenti all'interno del codice dell'app