Vous pouvez y parvenir avec certaines des fonctions json disponible dans postgresql.
Dans l'exemple avec db-fiddle fonctionnel ci-dessous, j'ai inclus des données de test supplémentaires.
Schéma (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]}]}');
Requête 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 |
---|
{"DestinationLists":[{"name":"ThirdTest","destinations":[{"Id":3},{"Id":5}]},{"name ":"SecondTest","destinations":[{"Id":103},{"Id":105}]}]} |
{"DestinationLists":[{"name":"TV3/TVNZ/CHOICE","destinations":[{"Id":183},{"Id":165}]}]} |
Modifier 1
En réponse à votre modification, le code ci-dessous peut être utilisé comme mise à jour de la déclaration. NB. Le CTE peut également être réécrit comme une sous-requête. Veuillez consulter l'exemple ci-dessous :
Schéma (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;
Après
SELECT * FROM my_table;
identifiant | dest |
---|---|
1 | {"DestinationLists":[{"name":"TV3/TVNZ/CHOICE","destinations":[{"Id":183},{"Id":165}]}]} |
2 | {"DestinationLists":[{"name":"SecondTest","destinations":[{"Id":103},{"Id":105}]},{"name":"ThirdTest", "destinations":[{"Id":3},{"Id":5}]}]} |
Modifier 2
Cette modification répond aux cas extrêmes où certaines destinations peuvent ne pas avoir de destinations et en tant que telles peuvent ne pas être mises à jour.
Pour tester, deux enregistrements supplémentaires ont été ajoutés, l'exemple d'enregistrement fourni où il y a deux listes de destinations nommées mais une seule a des destinations et un autre où il y a une liste de destinations nommées sans destinations.
La mise à jour garantit que s'il n'y a pas de modifications, c'est-à-dire qu'il existe des listes de destinations nommées sans destinations, celles-ci restent les mêmes. Il s'en assure en vérifiant si le nombre d'éléments de liste de destination nommés est le même que le nombre d'éléments de liste de destination vides. Comme tous sont vides, il filtre cet enregistrement de la mise à jour et réduit le nombre de mises à jour nécessaires sur la base de données. Un exemple de ceci est l'enregistrement numéro 4
La requête initiale a été modifiée pour tenir compte de ces listes vides car elles étaient filtrées avec l'approche précédente.
Schéma (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": []}]}');
Requête 1
SELECT '------ BEFORE -----';
?colonne? |
---|
------ AVANT ----- |
Requête n° 2
SELECT * FROM my_table;
identifiant | dest |
---|---|
1 | {"DestinationLists":[{"name":"TV3/TVNZ/CHOICE","destinations":[183,165]}]} |
2 | {"DestinationLists":[{"name":"SecondTest","destinations":[103,105]},{"name":"ThirdTest","destinations":[3,5]}]} |
3 | {"DestinationLists":[{"name":"TVNZ, Mediaworks, Choice","destinations":[]},{"name":"TVNZ, Discovery","destinations":[165,183,4155] }]} |
4 | {"DestinationLists":[{"name":"Quatrième test","destinations":[]}]} |
Requête n° 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;
identifiant | no_list_item | no_empty_list_item | nouveau_dest |
---|---|---|---|
1 | 1 | 0 | {"DestinationLists":[{"name":"TV3/TVNZ/CHOICE","destinations":[{"Id":183},{"Id":165}]}]} |
2 | 2 | 0 | {"DestinationLists":[{"name":"SecondTest","destinations":[{"Id":103},{"Id":105}]},{"name":"ThirdTest", "destinations":[{"Id":3},{"Id":5}]}]} |
3 | 2 | 1 | {"DestinationLists":[{"name":"TVNZ, Discovery","destinations":[{"Id":165},{"Id":183},{"Id":4155}]} ,{"name":"TVNZ, Mediaworks, Choice","destinations":[]}]} |
Requête n° 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;
Il n'y a aucun résultat à afficher.
Requête n° 5
SELECT '------ AFTER -----';
?colonne? |
---|
------ APRÈS ----- |
Requête n° 6
SELECT * FROM my_table;
identifiant | dest |
---|---|
4 | {"DestinationLists":[{"name":"Quatrième test","destinations":[]}]} |
1 | {"DestinationLists":[{"name":"TV3/TVNZ/CHOICE","destinations":[{"Id":183},{"Id":165}]}]} |
2 | {"DestinationLists":[{"name":"SecondTest","destinations":[{"Id":103},{"Id":105}]},{"name":"ThirdTest", "destinations":[{"Id":3},{"Id":5}]}]} |
3 | {"DestinationLists":[{"name":"TVNZ, Discovery","destinations":[{"Id":165},{"Id":183},{"Id":4155}]} ,{"name":"TVNZ, Mediaworks, Choice","destinations":[]}]} |
Faites-moi savoir si cela fonctionne pour vous.