MongoDB — проектирование документной схемы
Материал о проектировании документных схем в MongoDB. Базовый курс — MongoDB; синтаксис — справочник.
С чего начать
find или короткий pipeline. Поля, не участвующие в этих запросах, выносят в другую коллекцию.Ограничения, которые задают рамки:
- документ ≤ 16 МБ;
- чтение/запись идут целым документом (WiredTiger переписывает документ при изменении поля);
- атомарность по умолчанию — на уровне одного документа;
- индекс по массиву → multikey (отдельная запись индекса на элемент).
Кардинальность связей
| Связь | Вопросы | Типичное решение |
|---|---|---|
| 1:1 | Всегда читаются вместе? | Вложение или одна коллекция |
| 1:N | N небольшой и стабильный? | Массив в родителе |
| 1:N большой | Комментарии, события, логи | Отдельная коллекция + parentId, bucket |
| N:M | Друзья, подписки, роли | Коллекция рёбер { userId, targetId }, не массивы id в профиле |
| 1 : millions | Лента у знаменитости | Outlier pattern + overflow |
Для N:M массив followers: [ObjectId, …] в документе пользователя ломается при росте: 16 МБ, дорогие $push/$pull, hot document. Коллекция follows с индексами { followerId: 1 } и { followeeId: 1 } масштабируется; «список подписчиков» — find с лимитом или агрегация.
Нормализация и денормализация
Нормализация — несколько коллекций, связь через _id, при необходимости $lookup:
- плюс: одно место правды, дешевле обновлять каноническое поле;
- минус: несколько round-trip или тяжёлый
$lookupна hot path.
Денормализация — копии полей в документе-потребителе:
- плюс: один запрос на экран;
- минус: при смене канона нужно обновить много документов (batch, Change Stream, eventual consistency).
Пример «студент → занятия» (упрощённо):
- Три коллекции (
students,classes,studentClassesс массивом id) — три запроса на экран расписания. - Массив id в студенте — два запроса (
student+classes.find({ _id: { $in: … } })). - Полная денормализация — вложенные объекты занятий в
student.classes[], один запрос; синхронизация при смене аудитории затрагивает всех студентов.
Выбор зависит от соотношения чтение/запись и допустимой задержки согласованности копий.
Именованные шаблоны (patterns)
Краткий каталог. Развёрнутая таблица — в курсе MongoDB.
Bucket (ведро)
Поток метрик или событий группируют по интервалу (час, сутки) в один документ:
{
sensorId: "s-42",
bucketStart: ISODate("2025-05-30T14:00:00Z"),
bucketEnd: ISODate("2025-05-30T15:00:00Z"),
readings: [
{ t: ISODate("2025-05-30T14:01:00Z"), v: 23.1 },
{ t: ISODate("2025-05-30T14:02:00Z"), v: 23.4 }
]
}
С MongoDB 5.0+ для чистых временных рядов рассмотрите time series collection — отдельный тип с оптимизацией хранения.
Extended reference
Заказ хранит копии полей, нужных UI, без join при каждом открытии:
{
_id: ObjectId("..."),
customerId: ObjectId("..."),
shipTo: { name: "Иванов", city: "Уфа", zip: "450000" },
lines: [ { sku: "A1", qty: 2, title: "Кабель" } ]
}
customerId остаётся для синхронизации; shipTo — снимок на момент заказа.
Outlier (выброс)
У «тяжёлого» документа флаг hasOverflow: true; массив подписчиков/комментариев продолжается в user_overflow с тем же _id. Приложение по флагу делает второй запрос только для outliers.
Subset (подмножество)
В product — последние 10 отзывов; полный архив — product_reviews_archive. Каталог грузит быстро; «все отзывы» — отдельный endpoint.
Computed и Approximation
- Computed:
orderStats.totalSpentпересчитывается cron/триггером, а неaggregateна каждом профиле. - Approximation: счётчик просмотров +100 раз вместо +1 — меньше write contention.
Tree (материализованный путь)
Каталог: ancestors: ["Electronics", "Components", "Storage", "HDD"] + category: "HDD" для прямых детей; multikey-индекс по ancestors.
Управление схемой во времени
Schema-on-read не отменяет дисциплины:
- Версия документа — поле
schemaVersion: 2; код читает обе версии или мигрирует лениво при записи. - Batch migration —
find({ schemaVersion: { $lt: 2 } }).limit(1000)+updateв фоне; мониторинг прогресса. - JSON Schema validator на коллекции — новые поля только с
$jsonSchema/collMod:
db.createCollection("orders", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["customerId", "status"],
properties: {
status: { enum: ["new", "paid", "shipped"] }
}
}
},
validationLevel: "moderate",
validationAction: "error"
});
moderate — проверка только обновлений существующих полей; старые документы без новых полей не ломают insert.
Согласованность без транзакций
- Один документ — атомарный
$set/$inc. - Два документа — идempotent upsert + compensating action, или Change Stream + worker; multi-doc transaction — когда иначе нельзя.
- Read concern / write concern —
majorityдля «не потерять» запись при failover; см. §10 справочника.
Когда MongoDB — слабый выбор
- доминируют SQL-отчёты с десятками join на operational кластере;
- каждая операция требует строгих FK между многими коллекциями;
- данные естественно табличны и редко меняют форму (чистый OLTP в 3NF).
Подробнее — раздел в курсе.
Связанные материалы
- Микросервисы и выбор БД — bounded context и пары SQL/NoSQL
- 12 концепций — шардирование — ключ шарда и schema design связаны
- Официально: Data Modeling
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Нереляционные базы данных. Причины появления нереляционных систем. Выбор между SQL и NoSQL - сущности и отношения против событий, состояний и потоков в доменной модели. В NoSQL нет единого языка, как SQL для реляционных СУБД. Один и тот же продукт может принимать JSON (REST API), текстовый протокол (Redis), SQL-подобный диалект (CQL) или графовый язык (Cypher). MongoDB - документоориентированная СУБД для высоконагруженных и гибко меняющихся схем данных в распределённых сценариях. Справочник по MongoDB - ограничения документов, поле _id и правила имён ключей для корректной модели данных. Процесс установки и первое знакомство с технологией документоориентированной БД. Redis - in-memory хранилище структур данных в реальном времени с сетевым доступом и богатым набором типов. Тип "строка" в Redis - байтовая последовательность до 512 МБ для текста, счётчиков и сериализованных значений. Процесс установки и первое знакомство с технологией Redis. Таблица в реляционной модели и в Cassandra - различия схемы, строк и первичного ключа в NoSQL. Синтаксис CQL, конфигурация cassandra.yaml, nodetool, consistency levels и ограничения Apache Cassandra. Процесс установки и первое знакомство с технологией Apache Cassandra.История развития NoSQL-систем
Основы NoSQL
Синтаксис и знаки препинания в NoSQL-запросах
MongoDB - документоориентированная база данных
Справочник по MongoDB
Первые шаги с MongoDB
Redis - хранилище ключ-значение в памяти
Справочник по Redis
Первые шаги с Redis
Cassandra
Справочник по Cassandra
Первые шаги с Cassandra