Столкнулись ли вы с типами данных массивы и JSON в PostgreSQL
Что проверяют
Проверяют, отличаете ли вы json от jsonb и понимаете ли, когда динамическая колонка это удобство, а когда способ спрятать отсутствующую схему. Для Go добавляется вторая половина вопроса: как эти типы вообще доехать до структуры, потому что драйвер не сканирует их в []string или карту сам по себе.
Как отвечать
Скажите главное: json хранит текст как есть, включая пробелы и порядок ключей, и по содержимому не индексируется; jsonb хранит разобранное дерево, поддерживает операторы поиска и индекс GIN. В новых таблицах берут jsonb, а json остаётся, только когда важно сохранить исходный документ побайтово.
CREATE INDEX ON events USING gin (payload jsonb_path_ops);
SELECT * FROM events WHERE payload @> '{"type": "signup"}';
CREATE INDEX ON articles USING gin (tags);
SELECT * FROM articles WHERE tags @> ARRAY['golang'];Массив уместен для короткого однородного списка без собственных атрибутов: теги, роли. Как только у элемента появляется своё поле или по нему нужен внешний ключ, это отдельная таблица.
Про Go покажите, что знаете обвязку: jsonb читается в []byte или json.RawMessage и разбирается уже в коде, массив идёт через pq.Array или через типы pgx, а собственный тип с методами Value и Scan избавляет от ручных преобразований на каждом вызове.
Где спотыкаются
Ждут, что обычный индекс ускорит payload ->> 'type'. Не ускорит: нужен либо GIN на всю колонку, либо индекс по выражению, и тогда выражение в запросе должно совпадать с выражением в индексе буквально.
Кладут в jsonb то, что обновляется чаще всего. Обновление одного ключа переписывает документ целиком, а большой документ уезжает в TOAST и разжимается при каждом чтении. Горячие поля выносят в обычные колонки.
Сканируют text[] прямо в []string и получают ошибку преобразования: драйвер отдаёт колонку в текстовом виде базы, а не готовый список. Та же беда с колонкой, которая бывает пустой: в структуре нужен указатель или обёртка, иначе Scan падает на первой же такой строке.