Работа с JSON в SQL: PostgreSQL jsonb — практика

Мы просто и по делу рассказываем про ИИ-инструменты для работы: сравнения, пошаговые гайды, бесплатные альтернативы и реальные сценарии применения. Помогаем выбрать между ChatGPT, Gemini, Claude, локальными моделями и десятками узкоспециализированных сервисов — от дизайна и HR до аналитики и SEO. Меньше хайпа, больше практики и экономии времени каждый день.

postgresqljsonbsql

`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 и работе с данными.

🗣 Подборки каналов 🧠 Каталог ботов и приложений 🗺 Навигация

Читайте так же