Databases

MongoDB

MongoDB — документоориентированная NoSQL-СУБД, хранящая записи в виде JSON-подобных документов без обязательной единой схемы.

Что такое MongoDB

MongoDB (монго, mongo db) — документоориентированная NoSQL-СУБД. Вместо строк в таблицах со строгой схемой она хранит документы — JSON-подобные объекты, каждый со своим набором полей. Название от английского humongous (огромный).

Ключевая идея: объект приложения кладётся в базу как есть, целиком, без разбора на пять связанных таблиц и обратной сборки через JOIN.

// Документ в коллекции users
{
  _id: ObjectId("65a1f2e3c4d5b6a7f8091234"),
  email: "ivan@example.com",
  profile: { name: "Иван", city: "Москва" },   // вложенный объект
  tags: ["pro", "beta"],                        // массив прямо в поле
  lastLogin: ISODate("2026-07-01T10:00:00Z")
}

Соседний документ той же коллекции может иметь другой набор полей — база это допускает.

Терминология

Реляционная БД MongoDB
Таблица Коллекция (collection)
Строка Документ (document)
Колонка Поле (field)
JOIN Вложенность или $lookup
Первичный ключ _id

Физически документы хранятся в BSON — бинарном формате, который расширяет JSON типами ObjectId, Date, Decimal128 и бинарными данными. Поле _id создаётся автоматически, если не задано явно.

Базовые операции

db.users.insertOne({ email: "a@b.com", tags: ["new"] })

db.users.find({ "profile.city": "Москва" })          // поиск по вложенному полю
db.users.find({ tags: "pro" })                        // поиск по элементу массива
db.users.find({ age: { $gte: 18, $lt: 65 } })

db.users.updateOne(
  { email: "a@b.com" },
  { $set: { "profile.city": "Казань" }, $push: { tags: "vip" } }
)

db.users.createIndex({ email: 1 }, { unique: true })  // уникальный индекс
db.users.find({ email: "a@b.com" }).explain("executionStats")

Aggregation pipeline

Аналитические запросы строятся конвейером стадий, каждая обрабатывает выход предыдущей:

db.orders.aggregate([
  { $match:  { createdAt: { $gte: ISODate("2026-01-01") } } },  // фильтр
  { $group:  { _id: "$city", revenue: { $sum: "$total" } } },   // группировка
  { $sort:   { revenue: -1 } },
  { $limit:  10 }
])

$match ставят первой стадией не для красоты: он отсекает документы до тяжёлых операций и умеет пользоваться индексами, тогда как после $group индекса уже нет.

Схема данных: вложить или сослаться

Главное решение при проектировании — и главный источник проблем:

  • Вложить (embed) — подходит, когда данные читаются вместе с родителем, не растут бесконечно и не нужны отдельно. Комментарии в посте, адрес в профиле, позиции в заказе.
  • Сослаться (reference) — когда сущность самостоятельна, переиспользуется или коллекция растёт неограниченно. Пользователь и его заказы.

Ограничение, о которое спотыкаются: документ не может превышать 16 МБ. Массив, который растёт без предела (лента событий, лог), рано или поздно упрётся в лимит — такие данные выносят в отдельную коллекцию.

Соединение через $lookup существует, но это не полноценный JOIN: он медленнее, ограничен по возможностям, и строить на нём модель как в реляционной базе — верный способ получить худшее от обоих миров.

Транзакции и надёжность

Операции над одним документом атомарны всегда. Многодокументные ACID-транзакции появились в версии 4.0 и работают на replica set:

const session = db.getMongo().startSession()
session.startTransaction()
try {
  // операции над несколькими коллекциями
  session.commitTransaction()
} catch (e) {
  session.abortTransaction()
}

Они есть, но платны по производительности. Если приложению постоянно нужны транзакции через несколько коллекций — это сигнал, что данные реляционные и им место в PostgreSQL.

Ещё одна ручка надёжности — writeConcern: { w: 1 } подтверждает запись после primary, { w: "majority" } — после большинства узлов. Второе медленнее, но переживает падение primary без потери подтверждённых записей.

Масштабирование

  • Replica set — набор из primary и secondary-узлов с автоматическим выбором нового primary при отказе. Базовая конфигурация для продакшена: три узла, потому что для кворума нужно нечётное число. Репликация здесь же даёт чтение с secondary.
  • Sharded clusterшардирование по ключу через процессы mongos и конфигурационные серверы. Выбор shard key необратим по сути и определяет, будет ли нагрузка размазана или соберётся на одном шарде.

Лицензия и когда выбирать

С 2018 года MongoDB распространяется под SSPL — лицензией, которая не признана Open Source Initiative и ограничивает предоставление MongoDB как сервиса. Для собственной эксплуатации это не помеха; для встраивания в продукт условия стоит читать внимательно. Есть форк FerretDB, реализующий протокол MongoDB поверх PostgreSQL.

Mongo уместен, когда структура документов действительно разнородна и меняется, объект читается целиком по своему ключу, а горизонтальный рост важнее связей. Если данные табличные и связанные — реляционная база останется проще и надёжнее, тем более что jsonb в PostgreSQL закрывает потребность в документах без второй СУБД.

Связанные термины

Готовы запустить GPU-задачу?

Запустить GPU-сервер