`jsonb` в PostgreSQL — один из самых полезных инструментов, когда нужно хранить полуструктурированные данные: настройки, события, метаданные, ответы API, каталоги товаров. В отличие от `json`, тип `jsonb` хранится в бинарном виде, быстрее индексируется и удобнее для поиска.
Когда использовать `jsonb`
- если структура данных может меняться
- если часть полей необязательна
- если нужно быстро фильтровать по вложенным ключам
- если классическая нормализация таблиц будет слишком дорогой или громоздкой
Создание таблицы
create table events (
id bigserial primary key,
event_type text not null,
payload jsonb not null,
created_at timestamp default now()
);
Пример данных:
insert into events (event_type, payload) values
('order_created', '{"user_id": 42, "status": "new", "items": [{"sku":"A1","qty":2}]}'::jsonb);
Базовые операции
-
Получить значение по ключу:
select payload->'items' from events; -
Получить текстовое значение:
select payload->>'status' from events; -
Достать вложенное поле:
select payload#>>'{items,0,sku}' from events;
Фильтрация по JSON
select * from events
where payload->>'status' = 'new';
Проверка наличия ключа:
select * from events
where payload ? 'user_id';
Проверка содержимого:
select * from events
where payload @> '{"status":"new"}';
Это один из самых популярных запросов: как искать по полю внутри `jsonb`. Ответ — через `->>`, `@>`, или JSONPath.
Обновление JSON
Изменить значение внутри документа:
update events
set payload = jsonb_set(payload, '{status}', '"paid"')
where id = 1;
Добавить новое поле:
update events
set payload = jsonb_set(payload, '{source}', '"mobile_app"', true)
where id = 1;
Удалить ключ:
update events
set payload = payload - 'status'
where id = 1;
Индексы: обязательно для производительности ⚡
Если запросы по `jsonb` идут часто, без индексов будет больно.
GIN-индекс для поиска по содержимому:
create index idx_events_payload on events using gin (payload);
Индекс на конкретное поле:
create index idx_events_status on events ((payload->>'status'));
Первый хорош для `@>`, `?`, второй — для точной фильтрации и сортировки по конкретному ключу.
Когда `jsonb` — плохая идея 🚫
- если по полям нужны сложные JOIN
- если структура стабильна и известна заранее
- если данные критичны для строгой схемы и ограничений
- если все поля постоянно участвуют в аналитике
В таких случаях обычные колонки часто лучше.
Практический вывод 💡
`jsonb` в PostgreSQL — не замена реляционной модели, а сильное дополнение. Лучший подход в продакшене: ключевые поля выносить в отдельные колонки, а гибкие данные хранить в `jsonb`. Так вы получите и удобство, и производительность.
👀 В ленте стоит посмотреть подборку каналов про IT — там много полезного по PostgreSQL, backend и работе с данными.