Тема 05

Документоориентированные хранилища данных: MongoDB

Документоориентированные хранилища данных: MongoDB

В реляционных базах данных и строгих колоночных форматах Parquet каждая таблица имеет жесткую предопределенную схему (Schema-on-Write). Все строки обязаны иметь одинаковый набор столбцов, а добавление нового атрибута требует операции ALTER TABLE. Однако в реальных прикладных системах городского хозяйства и интернета вещей данные часто обладают высокой структурной неоднородностью.

Карточка аварийной заявки диспетчерской службы содержит базовые поля (адрес, время, заявитель), но состав специфических атрибутов зависит от характера происшествия: для прорыва трубопровода важны диаметр трубы, глубина залегания и давление, для отказа электроподстанции — фаза, напряжение и схема резервирования, а для заявки по лифтовому оборудованию — этажность, модель лебедки и коды ошибок контроллера. Попытка уложить такие данные в классическую реляционную схему приводит либо к созданию десятков полупустых таблиц, либо к антипаттерну Entity-Attribute-Value (EAV) с катастрофической потерей производительности 1.

Естественным решением для таких задач стал класс документоориентированных СУБД (Document Stores), ярким представителем которых является MongoDB 2.

Модель данных: документы и формат BSON

В MongoDB базовой единицей хранения является документ (Document), а совокупность документов образует коллекцию (Collection), аналогичную таблице реляционной СУБД.

Документы представлены в формате BSON (Binary JSON) — бинарной сериализации объектов JSON. В отличие от стандартного текстового JSON, формат BSON:

  1. Поддерживает расширенный набор типов данных: 64-битные целые (int64), даты с миллисекундной точностью (Date), бинарные массивы (binData), регулярные выражения и уникальные 12-байтные идентификаторы ObjectId.
  2. Явно сохраняет длину каждого поля и документа, что позволяет СУБД пропускать ненужные поля при парсинге без последовательного посимвольного чтения.
  3. Имеет жесткое ограничение на максимальный размер одного документа: 16 МБ (для хранения больших файлов вроде сканов актов и схем применяется протокол GridFS).

Пример документа аварийного инцидента в BSON:

{
  "_id": ObjectId("65e0a1b2c3d4e5f6a7b8c9d0"),
  "incident_number": "INC-2024-8841",
  "created_at": ISODate("2024-03-01T14:22:00Z"),
  "district": "Советский",
  "location": {
    "type": "Point",
    "coordinates": [84.9521, 56.4883]
  },
  "category": "водоснабжение",
  "equipment": {
    "pipe_diameter_mm": 300,
    "material": "чугун",
    "depth_m": 2.4
  },
  "tags": ["срочно", "утечка", "проезжая_часть"],
  "inspections": [
    {
      "inspector": "Иванов А. В.",
      "date": ISODate("2024-03-01T15:10:00Z"),
      "result": "требуется раскопка"
    }
  ],
  "status": "в_работе"
}

Встраивание (Embedding) против ссылок (Referencing)

В реляционных базах связь между сущностями реализуется через внешние ключи и нормализацию. В документоориентированных базах разработчик выбирает между двумя стратегиями:

  1. Встраивание документов и массивов (Embedding): Связанные данные хранятся прямо внутри родительского документа (например, массив актов осмотра inspections или координаты location).
    • Плюсы: Чтение всей информации об инциденте выполняется за одно дисковое обращение без соединений (JOIN). Атомарность обновления всего документа гарантируется из коробки.
    • Минусы: Дублирование данных при связях многие-ко-многим; риск превышения лимита 16 МБ при неконтролируемом росте массивов.
  2. Ссылки по идентификатору (Referencing): Хранение _id связанного документа из другой коллекции (например, ссылка на карточку обслуживающей организации). Используется при редких обращениях или очень больших объемах связанных данных.

Индексирование в MongoDB

Хранение документов на диске в движке WiredTiger организовано на основе B-деревьев. Для ускорения поиска MongoDB поддерживает богатый набор индексов:

  • Одиночные и составные индексы (Single / Compound Indexes): Позволяют быстро находить документы по значениям одного или нескольких полей:
    db.incidents.createIndex({ district: 1, created_at: -1 });
    
  • Многоключевые индексы (Multikey Indexes): Если индекс строится по полю, содержащему массив (например, tags: ["срочно", "утечка"]), MongoDB автоматически индексирует каждый элемент массива. Запрос db.incidents.find({ tags: "срочно" }) использует индекс по B-дереву.
  • Геопространственные индексы (2dsphere): Специализированные индексы для работы с координатами стандарта GeoJSON на сферической поверхности Земли. Поддерживают поиск ближайших объектов ($nearSphere) и проверку попадания в полигон ($geoWithin):
    db.incidents.createIndex({ location: "2dsphere" });
    
  • Текстовые индексы (Text Indexes): Обеспечивают полнотекстовый поиск по ключевым словам с учетом стемминга и стоп-слов.

Конвейер агрегации (Aggregation Pipeline)

В отличие от простых операций поиска find(), для сложного аналитического анализа в MongoDB используется конвейер агрегации (Aggregation Pipeline) 3. Документы последовательно проходят через цепочку стадий преобразования, аналогично конвейеру UNIX:

  Коллекция --> [$match] --> [$unwind] --> [$group] --> [$sort] --> Результат

Основные стадии конвейера

  1. $match: Фильтрация документов по предикату (аналог WHERE в SQL). Если $match стоит первым этапом, он эффективно использует B-дерево индексы.
  2. $project: Выборка, переименование полей или вычисление новых выражений (аналог SELECT).
  3. $group: Группировка документов по ключу _id с вычислением агрегатных функций: $sum, $avg, $min, $max, $push (аналог GROUP BY).
  4. $unwind: Разворачивание массива в поток отдельных документов. Если документ содержал массив из 3 элементов, стадия $unwind порождает 3 копии документа, каждая с одним элементом массива.
  5. $lookup: Левое внешнее соединение (Left Outer Join) с документами из другой коллекции.
  6. $facet: Выполнение нескольких независимых агрегационных конвейеров над одним набором данных в рамках одного запроса (удобно для фасетного поиска).

Пример агрегационного конвейера для расчета распределения типов аварий по районам:

db.incidents.aggregate([
  { $match: { status: "завершено", created_at: { $gte: ISODate("2024-01-01") } } },
  { $group: {
      _id: { district: "$district", category: "$category" },
      incident_count: { $sum: 1 },
      avg_repair_hours: {
        $avg: {
          $divide: [{ $subtract: ["$closed_at", "$created_at"] }, 3600000]
        }
      }
  }},
  { $sort: { incident_count: -1 } }
]);

Транзакции и архитектура высокой доступности

Исторически документные базы критиковали за отсутствие гарантий ACID для нескольких документов. Однако начиная с версии 4.0 MongoDB поддерживает многодокументные распределенные транзакции (Multi-Document ACID Transactions) с изоляцией Snapshot Isolation на базе движка WiredTiger 4.

Для обеспечения отказоустойчивости применяется механизм наборов реплик (Replica Sets):

  • Один первичный узел (Primary), принимающий все операции записи.
  • Несколько вторичных узлов (Secondary), асинхронно или синхронно реплицирующих журнал операций (oplog).
  • При отказе Primary вторичные узлы автоматически проводят голосование по алгоритму Raft и выбирают нового лидера менее чем за 3 секунды.

Для горизонтального масштабирования объемов хранения применяется шардирование (Sharding) на основе ключа шардирования (Shard Key) и маршрутизаторов mongos.

Итоги темы

MongoDB и документоориентированная модель представляют собой мощный инструмент для систем с динамической и слабоструктурированной природой данных. Формат BSON объединяет выразительность JSON с эффективностью бинарного представления, богатая система индексов (включая геопространственные 2dsphere) обеспечивает высокую скорость точечных запросов, а конвейер агрегации Aggregation Pipeline позволяет решать сложные аналитические задачи прямо внутри распределенной СУБД.

Литература

  1. Fowler M., Sadalage P. J. NoSQL Distilled: A Brief Guide to the Emerging World of Polyglot Persistence. — Addison-Wesley Professional, 2012. — Chapter 3: Document Databases 1.
  2. Chodorow K. MongoDB: The Definitive Guide: Powerful and Scalable Data Storage. — 3rd ed. — O'Reilly Media, 2020 2.
  3. MongoDB Documentation. The Aggregation Pipeline Architecture. — MongoDB Inc., 2024. https://www.mongodb.com/docs/manual/core/aggregation-pipeline/ 3.
  4. MongoDB Documentation. WiredTiger Storage Engine and Concurrency Control. — MongoDB Inc., 2024. https://www.mongodb.com/docs/manual/core/wiredtiger/ 4.