JSONB: отличаем отсутствующий ключ от явного null
Сервис получает частичное изменение профиля. Отсутствующий phone означает оставить телефон прежним, а phone: null — удалить его. После извлечения через ->> оба случая выглядят как SQL NULL, и обработчик не понимает намерение клиента.
Текстовое извлечение удобно для чтения значения, но не сохраняет все различия структуры JSON. Сначала проверьте наличие ключа оператором ?, затем извлекайте и применяйте значение. При таком порядке отсутствие поля остаётся отдельным состоянием.
Как изменить решение
WITH payloads(doc) AS (
VALUES ('{}'::jsonb), ('{"phone":null}'::jsonb),
('{"phone":"123"}'::jsonb)
)
SELECT doc ? 'phone' AS supplied,
jsonb_typeof(doc -> 'phone') AS json_type,
doc ->> 'phone' AS phone
FROM payloads;Для пустого объекта supplied будет false. Для явного JSON null supplied будет true, а json_type — строкой null. В обоих случаях phone окажется SQL NULL. Для строки 123 тип будет string, а текстовое значение сохранится.
Обновление должно опираться на два признака: передано ли поле и какое значение передано. Если строите документ из входного словаря до SQL, не удаляйте ключи с null автоматически: это уничтожает команду очистки. Проверка типа нужна отдельно, если число или массив недопустимы для телефона.
Что проверить на своих данных
Набор тестов состоит из пустого объекта, явного null, пустой строки и обычного значения. Сравните состояние профиля после каждого варианта. Пустая строка тоже требует бизнес-решения: хранить её, считать удалением или отклонять. JSON-оператор не выбирает это правило.
Такая модель полезна и для настроек, где значение может быть унаследовано, сброшено или переопределено. Не сводите эти состояния к одному COALESCE: подстановка старого значения при любом NULL мешает удалению. Сначала определите протокол изменения, затем подберите выражение SQL, которое сохраняет различия этого протокола.
Практика дальше
Следующая практика — запросы, где правильность зависит от нескольких источников и граничных случаев. В курсе «Продвинутый SQL» вы решаете 109 задач на JOIN, окна и CTE, сверяете отчёты и собираете витрину интернет-магазина. Запросы выполняются в браузере на SQLite с автоматической проверкой.
Посмотреть программу и практику курса
Источник: JSONB — официальная документация.
Другие задачи по теме: PostgreSQL: запись, блокировки и планы запросов.
Продолжить на практике
- Продвинутый SQL: сложные запросы и задачи для собеседований ↗
Продолжение базового SQL: сложные JOIN, оконные рамки, временные ряды, retention, воронки и рекурсивные CTE. Разбирайте примеры и пишите запросы с автоматической проверкой — от отдельных расчётов до витрины интернет-магазина.
