Я пытаюсь написать запрос на обновление глубоко вложенного JSON в моей базе данных PostgreSQL. Я все еще вступаю в борьбу со всей системой JSONB. В моем конкретном случае я пытаюсь определить и обновить несколько подразделов больших пакетов JSON. Определенная строка может глубоко включать массив. В этом массиве для многих элементов могут потребоваться изменения в соответствии с шаблоном.
Вот некоторый код для создания примера таблицы базы данных с одной строкой, которая выражает проблему, с которой я столкнулся. Это поддельные данные, поскольку фактические данные являются собственностью.
CREATE TABLE "Units" (
id serial primary key,
data jsonb
);
INSERT INTO "Units" (data)
VALUES
('
{
"animals": {
"mammals": [
{
"id": 0,
"population": 700
},
{
"id": 1
},
{
"id": 2,
"population": 500
}
],
"birds": [
{
"id": 3,
"population": 3000
},
{
"id": 4
}
]
}
}
');
В этом случае я хочу добавить ключ к каждому объекту в animals -> mammals
, который содержит ключ population
. Я хочу добавить новый ключ с именем extinct
, значение которого должно быть false
.
Вот запрос, который я разработал.
UPDATE "Units" as outside
SET data = jsonb_set(outside.data, ('{animals,mammals,' || (inside.ordinality - 1) || ',extinct}')::text[], 'false'::jsonb, true)
FROM (
SELECT id, ordinality
FROM "Units"
INNER JOIN jsonb_array_elements(data->'animals'->'mammals') with ordinality
ON id = id
WHERE value ? 'population' AND NOT (value ? 'extinct')
) as inside
WHERE outside.id = inside.id;
Я считаю этот запрос простым для понимания и понимания, а также достаточно эффективным для одноразовой автономной модификации. Однако у него есть один роковой недостаток. Поскольку UPDATE
работает только с каждой строкой один раз, этот запрос обновляет только одну из двух сущностей, в которых найден ключ population
. Этот запрос должен был бы выполняться дважды, чтобы обновить каждую сущность, найденную в первой строке. Теперь представьте, что это был более сложный объект JSON, и в этой таблице было намного больше строк. Это стало бы кошмаром для того, чтобы постоянно обновлять каждую последнюю сущность.
Как я могу настроить UPDATE
так, чтобы он обновлял каждую соответствующую сущность в каждой соответствующей строке?
Вот DBFiddle со всем выше.