Как несколько раз обновить глубоко вложенный JSON в одной строке в одном SQL UPDATE? - PullRequest
0 голосов
/ 09 июля 2019

Я пытаюсь написать запрос на обновление глубоко вложенного 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 со всем выше.

...