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);
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ