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

So ändern Sie die Struktur von jsonb-Daten, die in Postgres gespeichert sind

Sie können dies mit einigen der json-Funktionen erreichen verfügbar in postgresql.

In dem Beispiel mit funktionierendem db-fiddle unten habe ich einige zusätzliche Testdaten eingefügt.

Schema (PostgreSQL v13)

CREATE TABLE my_table (
  "dest" json
);

INSERT INTO my_table
  ("dest")
VALUES
  ('{"DestinationLists": [{"name": "TV3/TVNZ/CHOICE", "destinations": [183, 165]}]}'),
  ('{"DestinationLists": [{"name": "SecondTest", "destinations": [103, 105]},{"name": "ThirdTest", "destinations": [3, 5]}]}');

Abfrage 1

WITH expanded_data AS (
    SELECT
        dest::text, 
        json_build_object(
            'name',
             dl->>'name',
             'destinations',
             json_agg(
               json_build_object('Id',dld::text::int)
             )
        ) as dest_list_item
    FROM
        my_table, 
        json_array_elements(dest->'DestinationLists') dl,
        json_array_elements(dl->'destinations') dld
    GROUP BY
        dest::text,dl->>'name'
)
SELECT
    json_build_object(
        'DestinationLists',
        json_agg(dest_list_item)
    ) as new_dest
FROM
    expanded_data
GROUP BY
    dest::text;
new_dest
{"Ziellisten":[{"name":"ThirdTest","destinations":[{"Id":3},{"Id":5}]},{"name ":"ZweiterTest","Ziele":[{"Id":103},{"Id":105}]}]}
{"Ziellisten":[{"name":"TV3/TVNZ/CHOICE","destinations":[{"Id":183},{"Id":165}]}]}

Auf DB Fiddle ansehen

Bearbeiten 1

Als Antwort auf Ihre Bearbeitung kann der folgende Code als Update-From-Anweisung verwendet werden. NB. Der CTE kann auch als Unterabfrage umgeschrieben werden. Bitte sehen Sie sich das folgende Beispiel an:

Schema (PostgreSQL v13)

CREATE TABLE my_table (
  id bigserial,
  "dest" jsonb
);

INSERT INTO my_table
  ("dest")
VALUES
  ('{"DestinationLists": [{"name": "TV3/TVNZ/CHOICE", "destinations": [183, 165]}]}'),
  ('{"DestinationLists": [{"name": "SecondTest", "destinations": [103, 105]},{"name": "ThirdTest", "destinations": [3, 5]}]}');
WITH expanded_data AS (
    SELECT
        id, 
        json_build_object(
            'name',
             dl->>'name',
             'destinations',
             json_agg(
               json_build_object('Id',dld::text::int)
             )
        ) as dest_list_item
    FROM
        my_table, 
        jsonb_array_elements(dest->'DestinationLists') dl,
        jsonb_array_elements(dl->'destinations') dld
    GROUP BY
        id,dl->>'name'
), 
new_json AS (
    SELECT
        id,
        json_build_object(
            'DestinationLists',
            json_agg(dest_list_item)
        ) as new_dest
    FROM
        expanded_data
    GROUP BY
        id
)
UPDATE my_table
SET dest = new_json.new_dest
FROM new_json
WHERE my_table.id = new_json.id;

Nach

SELECT * FROM my_table;
id Ziel
1 {"Ziellisten":[{"name":"TV3/TVNZ/CHOICE","Ziele":[{"Id":183},{"Id":165}]}]}
2 {"Ziellisten":[{"name":"ZweiterTest","Ziele":[{"Id":103},{"Id":105}]},{"name":"DritterTest", "Ziele":[{"Id":3},{"Id":5}]}]}

Auf DB Fiddle ansehen

Bearbeiten 2

Diese Bearbeitung reagiert auf Grenzfälle, in denen einige Ziele möglicherweise keine Ziele haben und daher möglicherweise nicht aktualisiert werden.

Zum Testen wurden zwei zusätzliche Datensätze hinzugefügt, der bereitgestellte Beispieldatensatz, bei dem es zwei benannte Ziellisten gibt, aber nur eine mit Zielen und ein anderer, bei dem es eine benannte Zielliste ohne Ziele gibt.

Das Update stellt sicher, dass bei unveränderten, also benannten Ziellisten ohne Ziele, diese gleich bleiben. Sie stellt dies sicher, indem sie überprüft, ob die Anzahl benannter Ziellistenelemente gleich der Anzahl leerer Ziellistenelemente ist. Da alle leer sind, wird dieser Datensatz aus der Aktualisierung gefiltert und die Anzahl der für die Datenbank erforderlichen Aktualisierungen reduziert. Ein Beispiel hierfür ist die Datensatznummer 4

Die ursprüngliche Abfrage wurde geändert, um diese leeren Listen aufzunehmen, da sie mit dem vorherigen Ansatz gefiltert wurden.

Schema (PostgreSQL v13)

CREATE TABLE my_table (
  id bigserial,
  "dest" jsonb
);

INSERT INTO my_table
  ("dest")
VALUES
  ('{"DestinationLists": [{"name": "TV3/TVNZ/CHOICE", "destinations": [183, 165]}]}'),
  ('{"DestinationLists": [{"name": "SecondTest", "destinations": [103, 105]},{"name": "ThirdTest", "destinations": [3, 5]}]}'),
  ('{"DestinationLists": [{"name": "TVNZ, Mediaworks, Choice", "destinations": []}, {"name": "TVNZ, Discovery", "destinations": [165, 183, 4155]}]}'),
  ('{"DestinationLists": [{"name": "Fourth Test", "destinations": []}]}');

Abfrage 1

SELECT '------ BEFORE -----';
?column?
------ VORHER -----

Abfrage 2

SELECT * FROM my_table;
id Ziel
1 {"Ziellisten":[{"name":"TV3/TVNZ/CHOICE","destinations":[183,165]}]}
2 {"Ziellisten":[{"name":"ZweiterTest","Ziele":[103,105]},{"name":"DritterTest","Ziele":[3,5]}]}
3 {"Ziellisten":[{"name":"TVNZ, Mediaworks, Choice","destinations":[]},{"name":"TVNZ, Discovery","destinations":[165,183,4155] }]}
4 {"Ziellisten":[{"name":"Vierter Test","destinations":[]}]}

Abfrage 3

WITH expanded_data AS (
    SELECT
        id, 
        CASE
            WHEN COUNT(dld)=0 THEN 1
            ELSE 0
        END as name_has_empty_list_item,
        json_build_object(
            'name',
             dl->>'name',
             'destinations',
              CASE 
                  WHEN 
                       COUNT(dld)=0 
                  THEN 
                       to_json(array[]::json[])
                  ELSE
                       json_agg(
                           json_build_object('Id',dld::text::int )
                       )
              END
        ) as dest_list_item
    FROM
        my_table, 
        jsonb_array_elements(dest->'DestinationLists') dl
    LEFT JOIN
        jsonb_array_elements(dl->'destinations') dld ON 1=1
    GROUP BY
        id,dl->>'name'
), 
new_json AS (
    SELECT
        id,
        COUNT(dest_list_item) as no_list_item,
        SUM(name_has_empty_list_item) as no_empty_list_item,
        json_build_object(
            'DestinationLists',
            json_agg(dest_list_item)
        ) as new_dest
    FROM
        expanded_data
    GROUP BY
        id
    HAVING
        SUM(name_has_empty_list_item) <> COUNT(dest_list_item)
    
)
SELECT * FROM new_json;
id no_list_item no_empty_list_item neues_ziel
1 1 0 {"Ziellisten":[{"name":"TV3/TVNZ/CHOICE","Ziele":[{"Id":183},{"Id":165}]}]}
2 2 0 {"Ziellisten":[{"name":"ZweiterTest","Ziele":[{"Id":103},{"Id":105}]},{"name":"DritterTest", "Ziele":[{"Id":3},{"Id":5}]}]}
3 2 1 {"Ziellisten":[{"name":"TVNZ, Discovery","destinations":[{"Id":165},{"Id":183},{"Id":4155}]} ,{"name":"TVNZ, Mediaworks, Choice","destinations":[]}]}

Abfrage #4

WITH expanded_data AS (
    SELECT
        id, 
        CASE
            WHEN COUNT(dld)=0 THEN 1
            ELSE 0
        END as name_has_empty_list_item,
        json_build_object(
            'name',
             dl->>'name',
             'destinations',
              CASE 
                  WHEN 
                       COUNT(dld)=0 
                  THEN 
                       to_json(array[]::json[])
                  ELSE
                       json_agg(
                           json_build_object('Id',dld::text::int )
                       )
              END
        ) as dest_list_item
    FROM
        my_table, 
        jsonb_array_elements(dest->'DestinationLists') dl
    LEFT JOIN
        jsonb_array_elements(dl->'destinations') dld ON 1=1
    GROUP BY
        id,dl->>'name'
), 
new_json AS (
    SELECT
        id,
        json_build_object(
            'DestinationLists',
            json_agg(dest_list_item)
        ) as new_dest
    FROM
        expanded_data
    GROUP BY
        id
    HAVING
        SUM(name_has_empty_list_item) <> COUNT(dest_list_item)
)
UPDATE my_table
SET dest = new_json.new_dest
FROM new_json
WHERE my_table.id = new_json.id;

Es gibt keine anzuzeigenden Ergebnisse.

Abfrage #5

SELECT '------ AFTER -----';
?column?
------ NACH -----

Abfrage #6

SELECT * FROM my_table;
id Ziel
4 {"Ziellisten":[{"name":"Vierter Test","destinations":[]}]}
1 {"Ziellisten":[{"name":"TV3/TVNZ/CHOICE","Ziele":[{"Id":183},{"Id":165}]}]}
2 {"Ziellisten":[{"name":"ZweiterTest","Ziele":[{"Id":103},{"Id":105}]},{"name":"DritterTest", "Ziele":[{"Id":3},{"Id":5}]}]}
3 {"Ziellisten":[{"name":"TVNZ, Discovery","destinations":[{"Id":165},{"Id":183},{"Id":4155}]} ,{"name":"TVNZ, Mediaworks, Choice","destinations":[]}]}

Auf DB Fiddle ansehen

Lassen Sie mich wissen, ob dies für Sie funktioniert.