sql >> Database >  >> RDS >> PostgreSQL

Voeg een nieuw item in de JSONB-kolom in op basis van de waarde van een ander veld - postgres

Dit zou voldoende informatie moeten zijn om de zoekopdracht te voltooien:

Laten we de nepgegevens maken

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

Ontplof nu de array met jsonb_array_elements met ordinaliteit om de index en de eigenschap te krijgen

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

Het resultaat van deze zoekopdracht is:

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

Daar heb je de nodige informatie die je nodig hebt om de subelementen op te halen die je nodig hebt, evenals alle indexen die je nodig hebt voor je zoekopdracht.

Nu, bij de laatste bewerking, had je al de vraag die je wilde:

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 de plaats waar je de id gaat gebruiken, want dat zijn de rijen waarin je geïnteresseerd bent, en in de indexen die je uit de query hebt gehaald. Dus:

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;

Zoals je kunt zien, wordt dit gemakkelijk erg smerig.

Ik raad aan om ofwel een meer sql-benadering te gebruiken, dat wil zeggen functies in een tabel te hebben in plaats van in een json, een fk die dat aan je tabel koppelt... Als je echt de json moet gebruiken, bijvoorbeeld omdat het domein is echt complex en gedefinieerd op applicatieniveau en zeer flexibel. Dan zou ik aanraden om de updates in de app-code te doen




  1. Hoe tabellen vooraf in de INNODB-bufferpool te laden met MySQL?

  2. Hoe kan ik de functie gebruiken in mijn mysql-query?

  3. Zoeken tussen datums en tijden in SQL Server 2008

  4. Hoe een record invoegen en de nieuw gemaakte ID retourneren met een enkele SqlCommand?