Динамический размер поддокумента mongodb

Я использую mongodb и mongoose для своего веб-приложения. Веб-приложение используется для регистрации на соревнованиях по плаванию, и каждое соревнование может иметь Х количество гонок. Моя структура данных на данный момент:

{
  "_id": "1",
  "name": "Utmanaren",
  "location": "town",
  "startdate": "20150627",
  "enddate": "20150627"
  "race" : {
    "gender" : "m"
    "style" : "freestyle"
    "length" : "100"
  }
}

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

{
  "belongsTOId" : "1"
  "gender" : "m"
  "style" : "freestyle"
  "length" : "100"
}
{
  "belongsTOId" : "1"
  "gender" : "f"
  "style" : "butterfly"
  "length" : "50"
}

Есть ли способ создания и определения динамического количества рас в качестве поддокумента при использовании Mongodb?

Спасибо!

3 ответа

Решение

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

Давайте рассмотрим следующий пример, который отображает соревнования по плаванию и отношения с несколькими расами. Это демонстрирует преимущество встраивания по сравнению со ссылками, если вам нужно просматривать много объектов данных в контексте другого. В этом отношении "один ко многим" между данными о соревнованиях и гонках в соревновании участвуют несколько рас:

// db.competition schema
{
    "_id": 1,
    "name": "Utmanaren",
    "location": "town",
    "startdate": "20150627",
    "enddate": "20150627"
    "races": [
        {
            "gender" : "m"
            "style" : "freestyle"
            "length" : "100"
        },
        {           
            "gender" : "f"
            "style" : "butterfly"
            "length" : "50"
        }
    ]
}

Благодаря встроенной модели данных ваше приложение может получить полную информацию о соревнованиях по плаванию всего одним запросом. У этого дизайна есть и другие достоинства, одним из которых является локальность данных. Поскольку MongoDB хранит данные непрерывно на диске, размещение всех необходимых данных в одном документе гарантирует, что вращающимся дискам потребуется меньше времени для поиска в определенном месте на диске. Другое преимущество встроенных документов - атомарность и изоляция при записи данных. Чтобы проиллюстрировать это, скажем, вы хотите удалить соревнование со свойством гонки "style" со значением "butterfly", это можно сделать одной единственной (атомарной) операцией:

db.competition.remove({"races.style": "butterfly"});

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

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

// db.race schema
{
    "_id": 1,
    "competition_id": 1,
    "gender": "m",
    "style": "freestyle",
    "length": "100"
},
{
    "_id": 2,
    "competition_id": 1,
    "gender": "f",
    "style": "butterfly",
    "length": "50"
}

Вышеуказанный подход дает повышенную гибкость при выполнении запросов. Например, чтобы получить все дочерние документы гонки, где основной родительский объект competition имеет идентификатор 1 будет просто, просто создать запрос к коллекции race:

db.race.find({"competiton_id": 1});

Упомянутая выше нормализованная схема с использованием ссылочного подхода к документу также имеет преимущество, когда у вас есть отношения "один ко многим" с очень непредсказуемой арностью. Если у вас есть сотни или тысячи race документы по каждому competitionопция встраивания имеет так много недостатков, что касается пространственных ограничений, потому что чем больше документ, тем больше оперативной памяти он использует, а документы MongoDB имеют жесткий размер 16 МБ.

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

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

Ref:

Прикладные шаблоны проектирования MongoDB: примеры практического использования с ведущей базой данных NoSQL Рик Коупленд

Вставить один элемент в поле;

db.yourcollection.update( { $push: { "races": { "belongsTOId" : "1" , "gender" : "f" , "style" : "butterfly" , "length" : "50"} } } );

Чтобы вставить несколько элементов в поле, это позволяет дублировать в поле;

db.yourcollection.update( { $push: { "races": { $each: [ { "belongsTOId" : "1" , "gender" : "f" , "style" : "butterfly" , "length" : "50"}, { "belongsTOId" : "2" , "gender" : "m" , "style" : "horse" , "length" : "70"} ] } } } );

Толкать несколько предметов без дублирующихся предметов;

db.yourcollection.update( { $addToSet: { "races": { $each: [ { "belongsTOId" : "1" , "gender" : "f" , "style" : "butterfly" , "length" : "50"}, { "belongsTOId" : "2" , "gender" : "m" , "style" : "horse" , "length" : "70"} ] } } } );

Начиная с версии 2.4 $pushAll устарела, поэтому мы используем $each в $push вместо $pushAll.

Используя $ push, вы сможете сортировать и разрезать элементы. Вы можете проверить руководство mongodb.

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

  1. Храните массив ключей в основном документе.
  2. Вставьте вложенный документ и добавьте ключ в список или обновите список.
Другие вопросы по тегам