sql >> Databasteknik >  >> RDS >> PostgreSQL

Infoga nytt objekt i JSONB-kolumnen baserat på värdet för annat fält - postgres

Detta bör vara tillräckligt med information för att slutföra frågan:

Låt oss skapa skendata

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

Explodera nu arrayen med jsonb_array_elements med ordinalitet för att få indexet och egenskapen

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

Resultatet av denna fråga är:

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

Där har du den nödvändiga informationen som du behöver för att hämta underelementen som du behöver, såväl som alla index som du behövde för din fråga.

Nu, till den sista redigeringen, hade du redan frågan som du ville ha:

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

I den där du kommer att använda id:t, eftersom det är de rader som du är intresserad av, och i indexen fick du dem från frågan. Så:

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;

Som du kan se blir detta lätt väldigt otäckt.

Jag skulle rekommendera att antingen använda en mer sql-metod, det vill säga att ha funktioner i en tabell istället för inuti en json, en fk som länkar det till din tabell...Om du verkligen behöver använda json, till exempel, eftersom domänen är riktigt komplex och definierad på applikationsnivå och mycket flexibel. Då skulle jag rekommendera att göra uppdateringarna i appkoden




  1. Är det möjligt att använda användardefinierade aggregat (clr) med fönsterfunktioner (över)?

  2. Använda mySql via proxy-kast Orsakas av:java.sql.SQLException:Anropsbara uttalanden stöds inte. efter återanslutningen

  3. Kolumn finns inte i IN-satsen, men SQL körs

  4. Hur man beställer efter i SQL PIVOT