Você pode conseguir isso com algumas das funções json disponível no postgresql.
No exemplo com o db-fiddle funcionando abaixo, incluí alguns dados de teste adicionais.
Esquema (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]}]}');
Consulta nº 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}]}]} |
Visualizar no DB Fiddle
Editar 1
Em resposta à sua edição, o código abaixo pode ser usado como uma atualização da instrução. NB. O CTE também pode ser reescrito como uma subconsulta. Por favor, veja o exemplo abaixo:
Esquema (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;
Depois
SELECT * FROM my_table;
id | destino |
---|---|
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}]}]} |
Visualizar no DB Fiddle
Editar 2
Esta edição responde aos casos extremos em que alguns destinos podem não ter destinos e, portanto, podem não ser atualizados.
Para testar, foram adicionados dois registros adicionais, o registro de amostra fornecido onde há duas listas de destinos nomeados, mas apenas um possui destinos e outro onde há uma lista de destinos nomeados sem destinos.
A atualização garante que, se não houver alterações, ou seja, há listas de destinos nomeados sem destinos que permanecem os mesmos. Ele garante isso verificando se o número de itens da lista de destino nomeados é igual ao número de itens da lista de destino vazios. Como todos estão vazios, ele filtra esse registro da atualização e reduz o número de atualizações necessárias no banco de dados. Um exemplo disso é o número de registro
4
A consulta inicial foi modificada para acomodar essas listas vazias à medida que estavam sendo filtradas com a abordagem anterior.
Esquema (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": []}]}');
Consulta nº 1
SELECT '------ BEFORE -----';
?coluna? |
---|
------ ANTES ----- |
Consulta nº 2
SELECT * FROM my_table;
id | destino |
---|---|
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":"Quarto teste","destinations":[]}]} |
Consulta 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;
id | no_list_item | no_empty_list_item | new_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":[]}]} |
Consulta 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;
Não há resultados a serem exibidos.
Consulta nº 5
SELECT '------ AFTER -----';
?coluna? |
---|
------ DEPOIS ----- |
Consulta nº 6
SELECT * FROM my_table;
id | destino |
---|---|
4 | {"DestinationLists":[{"name":"Quarto teste","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":[]}]} |
Visualizar no DB Fiddle
Deixe-me saber se isso funciona para você.