PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Fügen Sie ein neues Element in die JSONB-Spalte ein, basierend auf dem Wert eines anderen Felds – postgres

Diese Informationen sollten ausreichen, um die Abfrage abzuschließen:

Lassen Sie uns die Scheindaten erstellen

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

Explodieren Sie nun das Array mit jsonb_array_elements mit Ordinalität, um den Index und die Eigenschaft

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

Das Ergebnis dieser Abfrage ist:

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

Dort haben Sie die notwendigen Informationen, die Sie benötigen, um die benötigten Unterelemente abzurufen, sowie alle Indizes, die Sie für Ihre Abfrage benötigen.

Nun zur letzten Bearbeitung, Sie hatten bereits die gewünschte Abfrage:

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 dem verwenden Sie die ID, da dies die Zeilen sind, an denen Sie interessiert sind, und in den Indizes, die Sie aus der Abfrage erhalten haben. Also:

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;

Wie Sie sehen können, wird dies sehr unangenehm.

Ich würde empfehlen, entweder einen mehr SQL-Ansatz zu verwenden, das heißt, Funktionen in einer Tabelle statt in einem JSON zu haben, ein fk, das das mit Ihrer Tabelle verknüpft ... Wenn Sie zum Beispiel wirklich den JSON verwenden müssen, weil die Domäne ist sehr komplex und auf Anwendungsebene definiert und sehr flexibel. Dann würde ich empfehlen, die Updates innerhalb des App-Codes durchzuführen