MongoDB. Модели представления данных

Введение

Первым и главным шагом при проектировании приложений является понимание того как будут представлены ваши данные. Как будут организована объектная модель базы данных, в коллекциях или документах? Плохо спроектированное представление данных может замедлить ваше приложение, заставив вас делать тяжелые и сложные запросы для получения необходимых данных.

Что такое НОРМАЛИЗАЦИЯ?

Нормализация — это основной принцип организации данных в реляционных базах данных, в основе которого заключается снижении избыточности данных в одной таблице путем связывания разделенных данных из других таблиц (коллекций) между собой через ссылки (индексы) сохраняя при этом целостность данных между собой. По большому счету это структура справочников данные которых связаны.

normalize_data

Когда вы нормализуете свои данные, то они разделяются на несколько коллекций со ссылками между этими коллекциями (таблицами). Каждая часть данных будет в коллекции, но несколько документов будут ссылаться на нее. Это означает, что для изменения ваших данных вам нужно только обновить один документ, потому что эти данные определяются только один раз. Тем не менее, у MongoDB нет каких-либо средств связывания данных, таких как в реляционных SQL базах. Поэтому, если вам нужны данные из нескольких коллекций, вам нужно будет выполнить несколько запросов.

Давайте рассмотрим пример нормализации данных в документальных системах (NoSQL).

У нас есть коллекция пользователей. Мы сохраняем предпочтения каждого пользователя в коллекции accountsPref. Мы храним каждую статью, написанную пользователями в коллекции статей.

В нормализованном примере наши коллекции могут выглядеть так:

db.users.findOne({_id: userId})
{
   _id: ObjectId("5977aad83abbae8aef44b47b"),
   name: "John Doe",
   email: "johndoe@gmail.com",
   articles: [
        ObjectId("5977aad83abbae8aef44b47a"),
        ObjectId("5977aad83abbae8aef44b478"),
        ObjectId("5977aad83abbae8aef44b477")
   ],
   accountsPref: ObjectId("5977aad83abbae8aef44b476")
}

db.accountsPref.findOne({_id: id})
{
    id: ObjectId("5977aad83abbae8aef44b490"),
    userId: ObjectId("5977aad83abbae8aef44b47b"),
    showFriends: true,
    notificationsOne: false,
    style: "light"
}

Мы храним ссылки на каждую часть данных в наших коллекциях. Это частый способ сделать что-то в реляционной базе данных. Но, в MongoDB, хранить данные таким образом не очень принято. Для получения требуемых данных требуется много запросов. Чтобы получить информацию о пользователе, вам нужно будет сделать 3 обращения к базе данных. Один для пользователей, один для аккаунтов, другой для статей.

ДЕНОРМАЛИЗАЦИЯ

Для того чтобы оптимизировать хранения данных для документальных типов хранения необходимо осуществит денормализацию. Например, мы хотим оптимизировать свои запросы к базе данных. Нам не хочется обращаться к базе 3 раза, чтобы получить информацию. Мы могли бы сохранить настройки учетных записей каждого пользователя в виде встроенного документа, например:

 

{
  _id: ObjectId("5977aad83abbae8aef44b47b"),
  name: "John Doe",
  email: "johndoe@gmail.com",
  articles: [
    ObjectId("5977aad83abbae8aef44b47a"),
    ObjectId("5977aad83abbae8aef44b478"),
    ObjectId("5977aad83abbae8aef44b477")
  ],
  accountsPref: {
    style: "light",
    showFriends: true,
    notificationsOn: false
  }
}

Преимущество этого подхода заключается в том, что вам нужно уже на один запрос меньше для получения информации. Недостатком является то,  что такой документ занимает больше места и его сложнее синхронизировать (т.е. сохранять целостность данных при обнолвении). Например, мы решили, что светлый стиль должен быть переименован в темный. Мы должны были бы обновить каждый отдельный документ, в котором был бы user.accountsPref.style.

Однако можно использовать гибридную модель ссылок и встроенных (вложенных) данных. Вы можете сохранить поддокумент, в котором добавляете ссылку на настройки своего аккаунта. Но часто используемые поля необходимо добавлять в виде поля, а не ссылкой. Если вы знаете, что в вашем приложении часто используется только style, вы можете сделать это:

 

{
  _id: ObjectId("5977aad83abbae8aef44b47b"),
  name: "John Doe",
  email: "johndoe@gmail.com",
  articles: [
    ObjectId("5977aad83abbae8aef44b47a"),
    ObjectId("5977aad83abbae8aef44b478"),
    ObjectId("5977aad83abbae8aef44b477")
  ],
  accountsPref: {
    _id: ObjectId("5977aad83abbae8aef44b490"),
    style: "light"
  }
}

Это может быть очень удобным подходом потому-что в процессе разработки или последующей доработке приложения может возникнуть необходимость внесения изменений в объектную модель данных. Если вы захотите включить дополнительные поля или удалить существующие из встроенного документа, то проблем с этим не возникнет.

Выводы

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

Должны ли вы сохранять настройки учетных записей в документе каждого пользователя? Вообще-то да. Это относится только к этому пользователю. Вероятно это тоже не изменится.

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

Вот некоторые рекомендации, которые помогут вам при рассмотрении этой проблемы:

Когда стоит использовать встраиваемую модель данных:

  • У вас есть небольшие поддокументы
  • Ваши данные не должны регулярно меняться
  • Вам не требуется быстрая согласованность данных
  • Количество документов увеличивается равномерно
  • Эти данные необходимы для выполнения второго запроса
  • Вам необходима большая скорость чтения

Когда стоит использовать реляционную модель данных:

  • У вас большие поддокументы
  • Ваши данные часто меняются
  • Вам нужны ваши данные, чтобы быть актуальными
  • Количество документов быстро увеличивается
  • Сложные фильтры выборки данных
  • Вам необходима высокая скорость записи данных

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *