JavaRush /Курсы /SQL SELF /Объединение и модификация JSON-объектов с оператором || и...

Объединение и модификация JSON-объектов с оператором || и функцией jsonb_concat()

SQL SELF
34 уровень , 0 лекция
Открыта

Если JSONB — это волшебный сундук, куда мы кладём данные, то || и jsonb_concat() — инструменты, позволяющие объединять такие сундуки или изменять их содержимое. В реальной жизни вам может потребоваться объединить несколько JSON-объектов, добавить данные из одного в другой или объединить массивы в единый список.

Например, представьте, что у вас есть два JSONB-объекта:

{"name": "Alice", "age": 25}

и

{"city": "Wonderland", "hobbies": ["reading", "chess"]}

Вы хотите получить:

{"name": "Alice", "age": 25, "city": "Wonderland", "hobbies": ["reading", "chess"]}

Или объединить два массива JSONB:

[1, 2, 3]

и

[4, 5, 6]

чтобы результат выглядел как:

[1, 2, 3, 4, 5, 6]

Всё это делается с помощью || или jsonb_concat(). Давайте разбираться как.

Оператор || для объединения JSONB

Оператор || позволяет объединять два JSONB-объекта или массива в PostgreSQL. Он простой, быстрый и лёгкий в использовании. Вот основные правила его работы:

  • Если объединяются два JSONB-объекта, то результирующий объект будет содержать ключи и значения обоих объектов.
  • Если ключи пересекаются, значение из правого операнда заменяет значение из левого.
  • Если объединяются JSONB-массивы, то элементы левого и правого массива объединяются в один массив.

Пример 1: Объединение двух JSONB-объектов

SELECT '{"name": "Alice", "age": 25}'::jsonb || '{"city": "Wonderland", "hobbies": ["reading", "chess"]}'::jsonb AS merged_object;

Результат:

{"name": "Alice", "age": 25, "city": "Wonderland", "hobbies": ["reading", "chess"]}

Пример 2: Обновление значений при совпадении ключей

SELECT '{"name": "Alice", "age": 25}'::jsonb || '{"age": 30, "city": "Wonderland"}'::jsonb AS updated_object;

Результат:

{"name": "Alice", "age": 30, "city": "Wonderland"}

Обратите внимание, что значение ключа "age" из правого объекта заменило значение из левого.

Пример 3: Объединение массивов

SELECT '[1, 2, 3]'::jsonb || '[4, 5, 6]'::jsonb AS merged_array;

Результат:

[1, 2, 3, 4, 5, 6]

Функция jsonb_concat() для объединения JSONB

Функция jsonb_concat() работает аналогично оператору ||, но предоставляет гибкость, если вам нужно использовать её в функциях, триггерах или динамических запросах. Она принимает два аргумента типа JSONB и возвращает объединённый результат.

Пример: использование jsonb_concat()

SELECT jsonb_concat('{"a": 1, "b": 2}'::jsonb, '{"b": 3, "c": 4}'::jsonb) AS combined;

Результат:

{"a": 1, "b": 3, "c": 4}

Объединение объектов и массивов: особенности и нюансы

При объединении объектов с совпадающими ключами следует понимать, что значения из правого объекта имеют приоритет.

Например:

SELECT '{"key1": "value1"}'::jsonb || '{"key1": "value2"}'::jsonb AS result;

Результат:

{"key1": "value2"}

Если вы хотите избежать замены значений, следует хранить такие данные в отдельных ключах или использовать другой подход (например, массив).

А вот массивы всегда объединяются путём добавления элементов из правого массива к левому. Например:

SELECT '["a", "b"]'::jsonb || '["c", "d"]'::jsonb AS result;

Результат:

["a", "b", "c", "d"]

Если внутри массива есть объекты, порядок объектов сохраняется:

SELECT '[{"id": 1}, {"id": 2}]'::jsonb || '[{"id": 3}]'::jsonb AS result;

Результат:

[{"id": 1}, {"id": 2}, {"id": 3}]

Практические примеры

Обновление профиля пользователя. Предположим, у нас есть таблица users, где профили хранятся в формате JSONB:

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    profile JSONB
);

INSERT INTO users (profile) VALUES ('{"name": "Alice", "age": 25}');

Теперь мы хотим добавить город проживания:

UPDATE users 
SET profile = profile || '{"city": "Wonderland"}'
WHERE id = 1;

Результат запроса:

{"name": "Alice", "age": 25, "city": "Wonderland"}

Объединение данных о заказах. Пусть у нас есть таблица orders:

CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    details JSONB
);

INSERT INTO orders (details) VALUES ('{"items": [{"product": "laptop", "quantity": 1}]}');

Теперь мы добавляем ещё один продукт в заказ:

UPDATE orders
SET details = jsonb_set(
    details,
    '{items}',
    details->'items' || '[{"product": "mouse", "quantity": 2}]'::jsonb
)
WHERE id = 1;

Результат запроса:

{"items": [{"product": "laptop", "quantity": 1}, {"product": "mouse", "quantity": 2}]}

Различия между || и jsonb_concat()

Функционально оператор || и функция jsonb_concat() идентичны. Используйте ||, если пишете простые запросы, так как запись более лаконична. Функция jsonb_concat() удобна в случаях, когда вам нужно явно вызывать её внутри программы или триггера.

Типичные ошибки и способы их предотвращения

Ошибка: попытка объединить несовместимые типы.

SELECT '{"key": "value"}'::jsonb || '["value"]'::jsonb;

Результат:

ERROR:  cannot concatenate jsonb objects and arrays

Здесь слева находится объект, а справа массив — PostgreSQL не может их просто так объединить. Чтобы операция сработала, оба операнда должны быть одного типа: либо два объекта, либо два массива.

Упущение: отсутствие индексов при работе с JSONB

Если вы часто фильтруете данные по значениям внутри JSONB-полей, а индексов нет — запросы могут сильно тормозить. Это не ошибка в классическом смысле, но последствия для производительности — очень ощутимы. Не забудьте использовать GIN-индексы:

CREATE INDEX idx_profile_data ON employees USING gin(profile);
2
Задача
SQL SELF, 34 уровень, 0 лекция
Недоступна
Обновление JSONB-объекта с учётом замены ключей
Обновление JSONB-объекта с учётом замены ключей
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ