Работа с внешними ключами в MongoDB: советы и методы

Пройдите тест, узнайте какой профессии подходите и получите бесплатную карьерную консультацию
В конце подарим скидку до 55% на обучение
Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

MongoDB не поддерживает механизм внешних ключей в классическом их понимании. В качестве замены обычно используются так называемые ручные ссылки, которые создают связи между документами в разных коллекциях.

В качестве примера можно привести отношение, где ObjectID документа хранится как ссылка в другом документе:

json
Скопировать код
// Документ пользователя в коллекции "users"
{ "_id": ObjectId("user123"), "name": "Джон Доу" }

// Документ заказа в коллекции "orders", связанный с пользователем Джон Доу
{ "product": "Виджет", "quantity": 1, "user_id": ObjectId("user123") }

Для реализации соединений, аналогичных тем, что используются в SQL, в MongoDB рекомендуется использовать оператор $lookup:

JS
Скопировать код
db.orders.aggregate([
  { $lookup: {
    from: "users",
    localField: "user_id", // поле с ID пользователя в "orders"
    foreignField: "_id",   // поле с ID пользователя в "users"
    as: "userDetails"      // псевдоним для результата соединения
  }}
])

Таким образом можно имитировать отношения между сущностями, однако автоматическую целостность связей это не гарантирует. За все отвечает логика вашего приложения.

Стратегии моделирования данных

В MongoDB процесс создания модели данных зависит от следующих принципов:

  • Денормализация: Ускоряет чтение и упрощает запросы за счет включения связанных данных непосредственно в документ.

  • Ручные ссылки: Обеспечивают связь между документами с помощью массивов ObjectID, предлагая таким образом гибкий подход к управлению схемами.

  • Денормализация против ссылок: В этом вопросе всегда есть баланс. Отношения "один ко многим" в большинстве случаев предпочтительнее реализовывать с использованием внедренных документов, в то время как отношения "один к миллионам" требуют ручных ссылок.

  • Операции изменения: MongoDB делегирует каскадные обновления и удаления на уровень приложения, что является особо важным в рамках интенсивных операций записи.

  • Проектирование схемы: Необходимо придерживаться "шести правил", предложенных MongoDB для эффективного проектирования схемы. Очень важной является принципиальная дилемма: включение документов или использование ссылок – решение должно быть осознанным.

ORM под прожекторами

Фреймворки ORM и ODM, такие как Mongoid, MongoMapper и Mongoose, упрощают управление соотношениями между данными:

  • В Mongoid: – embeds_many и embedded_in обеспечивают создание встроенных документов. – Отношения belongs_to и has_many реализуются аналогично тому, как они реализуются в SQL.

  • В Mongoose: – С помощью метода Populate автоматически выполняется замена путей в документе на связанные данные. – Виртуальные поля могут служить реляционными связями и подгружать дополнительные данные.

Защита целостности данных на уровне приложения

Из-за отсутствия встроенных механизмов ограничений в MongoDB ответственность за поддержание целостности данных лежит на приложении:

  • Каскадные обновления: При удалении одного из документов все связанные с ним документы остаются без изменений, поэтому необходим контроль за "сиротскими" записями.

  • Согласованность: Для того чтобы данные были согласованы, необходимо ввести специальные функции и промежуточное программное обеспечение (middleware).

  • Некорректные ссылки: Приложение должно уметь очищать или воссоздавать связи, если связанные документы были удалены.

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

Проблема создания связей между большим набором данных заключается в необходимости балансировать между использованием ссылок и денормализацией:

  • Производительность ссылок: Разрешение большого количества ссылок может привести к снижению производительности из-за увеличения нагрузки на выполнение запросов.

  • Затраты пространства при денормализации: Денормализация ускоряет чтение, но может усложнить хранение данных и поддержание их согласованности.

Продвинутые соглашения для ссылок

Для создания ссылок, помимо прямого использования ObjectID, MongoDB предлагает:

  • DBRef: Стандартизированный метод создания ссылок через поля "$ref", "$id" и "$db".

  • Имитация DBRef: Создание ссылок, подобных DBRef, но без применения специфического типа DBRef, для большей гибкости.

  • Фреймворк агрегации: Для решения сложных задач используйте фреймворк агрегации для создания графов документов или манипулирования связанными данными.

Визуализация

Визуально MongoDB можно представить в виде архипелага островов 🏝️, на каждом из которых расположены домики 🏠 (документы).

Если в SQL мире внешние ключи создают прочные мосты между домиками на разных островах 🌉:

🏠 1 на Острове А = 🌉 -> 🏠 А на Острове В

То в MongoDB монолитных мостов нет, и вместо этого документы связываются схоже с ситуацией, когда лодки следуют за компасом 🚣:

С 🏝️ А = 🚣 -> на 🏝️ B

Такая гибкость в организации структуры данных требует обдуманного подхода к управлению связями.

Управление обновлениями и удалением данных

В MongoDB, где нет встроенных каскадных операций, целесообразно использовать следующие практики управления данными:

  • Пакетное обновление: Запустите обновления для всех связанных документов при изменении одного из них.

  • Логика транзакций: Можно использовать транзакционные возможности MongoDB для координирования изменений в нескольких коллекциях.

  • Хуки и Middleware: Реализация методов предварительной и последующей обработки помогает автоматизировать процедуры обновления и удаления связанных документов.

Производительность и оптимизация

Для оптимизации запросов в MongoDB рекомендуется:

  • Индексы: Создавайте индексы на полях, используемых для ссылок и в операциях $lookup. Это ускоряет выполнение запросов.

  • Ключи шардинга: Правильно подобранные ключи шардинга обеспечивают горизонтальное масштабирование и уменьшают количество межшардовых запросов.

  • Профиль чтения/записи: Проектируйте схему данных, ориентируясь на особенности чтения и записи, которые характерны для вашего приложения.

Полезные материалы

  1. Database References — MongoDB Manual
  2. 6 Rules of Thumb for MongoDB Schema Design | MongoDB Blog
  3. MongoDB relationships: embed or reference? – Stack Overflow
  4. MongoDB Courses and Trainings | MongoDB University
  5. $lookup (aggregation) — MongoDB Manual
  6. Data Modeling — MongoDB Manual