теория
У документной модели репутация «schemaless» — «без схемы». Это, если честно, миф. Код, который читает документ, всё равно предполагает структуру: написал doc.attributes.fat_percent — вот тебе и схема. Так что вопрос не «есть схема или нет», а кто и когда её проверяет:
Меняются они тоже по-разному. Документная база: просто начинаешь писать новые документы по-новому, а в коде появляется ветка для старых (if (!doc.first_name) …) — и живёт там вечно, во всех местах чтения. Реляционная: миграция. Добавить колонку почти везде дёшево, а вот UPDATE всех строк большой таблицы — операция, которую планируют заранее.
Schema-on-read выигрывает, когда записи и правда разные по форме: типов объектов много, заводить таблицу под каждый непрактично — ровно наш случай с атрибутами категорий. А когда структура у всех одинаковая, явная схема — это бесплатная документация и валидация в подарок.
Есть и третий полюс — . Она для данных, где many-to-many повсюду, а запросы — обходы неизвестной заранее длины: «друзья друзей», «все локации в пределах США». Такой запрос — четыре строки на Cypher (язык запросов графовых баз) против тридцати строк рекурсивного SQL. Каталогу «Ярмарки» это не нужно: связей у товара наперечёт и на фиксированную глубину. Тащить его в графовую базу — мода, а не решение.
И ещё одна идея — она пригодится позже, но познакомимся сейчас. Представь, что ты хранишь не текущее состояние, а полный журнал случившихся событий — это . А для чтения держишь отдельные, удобные под запрос представления — это . Принцип шире самих паттернов: представление для записи и представление для чтения не обязаны совпадать. Фасетный поиск Леры — как раз такое производное представление: отдельный индекс, который перестраивается из базы.
Вывод простой и освобождающий: универсальной модели данных не существует. Её выбирают по форме данных и паттерну запросов — не по моде и не по последнему подкасту. А границы давно размылись: PostgreSQL умеет с индексами по полям внутри документа, MongoDB научился джойнам. Гибрид — не трусливый компромисс, а взрослый ответ.