Подтвердить что ты не робот

Заселение Mongoose vs вложенность объекта

Есть ли разница в производительности (время процесса запроса) между использованием Mongoose population и прямым включением объекта? Когда каждый должен использоваться?

Пример популяции Mongoose:

var personSchema = Schema({
  _id     : Number,
  name    : String,
  stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

var storySchema = Schema({
  _creator : { type: Number, ref: 'Person' },
  title    : String,
});

Пример вложенности объекта Mongoose:

var personSchema = Schema({
  _id     : Number,
  name    : String,
  stories : [storySchema]
});

var storySchema = Schema({
  _creator : personSchema,
  title    : String,
});
4b9b3361

Ответ 1

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

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

"Не волшебная" часть состоит в том, что по сути дела, что происходит под обложками, заключается в том, что когда вы ссылаетесь на другой источник, функция populate делает дополнительные запросы/запросы к этой "связанной" коллекции, чтобы "объединить" эти результаты родительского объекта, который вы получили. Вы можете сделать это сами, но метод для удобства упрощения задачи. Очевидное соображение "производительности" заключается в том, что нет никакой обратной поездки в базу данных (экземпляр MongoDB), чтобы получить всю информацию. Всегда есть более одного.

В качестве примера возьмите две коллекции:

{ 
    "_id": ObjectId("5392fea00ff066b7d533a765"),
    "customerName": "Bill",
    "items": [
        ObjectId("5392fee10ff066b7d533a766"),
        ObjectId("5392fefe0ff066b7d533a767")
    ]
}

И пункты:

{ "_id": ObjectId("5392fee10ff066b7d533a766"), "prod": "ABC", "qty": 1 }
{ "_id": ObjectId("5392fefe0ff066b7d533a767"), "prod": "XYZ", "qty": 2 }

"Лучшее", которое может быть сделано с помощью "ссылочной" модели или использования населенности (под капотом), таково:

var order = db.orders.findOne({ "_id": ObjectId("5392fea00ff066b7d533a765") });
order.items = db.items.find({ "_id": { "$in": order.items } ).toArray();

Таким образом, для "объединения" этих данных есть явно "по крайней мере" два запроса и операции.

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

Затем данные скорее выглядят так (по сравнению с приведенным выше примером):

{ 
    "_id": ObjectId("5392fea00ff066b7d533a765"),
    "customerName": "Bill",
    "items": [
        { "_id": ObjectId("5392fee10ff066b7d533a766"), "prod": "ABC", "qty": 1 },
        { "_id": ObjectId("5392fefe0ff066b7d533a767"), "prod": "XYZ", "qty": 2 }
    ]
}

Поэтому на самом деле получение данных - это всего лишь вопрос:

db.orders.findOne({ "_id": ObjectId("5392fea00ff066b7d533a765") });

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

Вложение

  • Общий размер документа со встроенными данными, как правило, не должен превышать 16 Мбайт памяти (предел BSON) или иначе (в качестве ориентира) имеют массивы, содержащие 500 или более записей.

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

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

Referencing

  • Связанные данные всегда будут превышать предел BSON на 16 МБ. Вы всегда можете рассматривать гибридный подход "bucketing", но общий жесткий предел основного документа не может быть нарушен. Обычными случаями являются "пост" и "комментарии", в которых ожидается, что активность "комментариев" будет очень большой.

  • Связанные данные требуют регулярного обновления. Или, по сути, случай, когда вы "нормализуетесь", потому что эти данные "разделяются" среди многих родителей, а "связанные" данные часто изменяются настолько, что было бы нецелесообразно обновлять встроенные элементы в каждом "родительском", где происходит этот "дочерний" элемент, Более простой случай - просто указать "ребенок" и внести изменения один раз.

  • Существует четкое разделение чтений и записей. В случае, когда, возможно, вы не будете всегда требовать эту "связанную" информацию при чтении "родителя" или иначе, чтобы не нужно всегда изменять "родительский" при написании ребенку, может быть веская причина отделить модель как указано. Кроме того, если есть общее желание обновить сразу несколько "поддокументов", в которых эти "поддокументы" фактически ссылаются на другую коллекцию, то довольно часто реализация более эффективна, когда данные находятся в отдельном коллекция.

Таким образом, на самом деле существует гораздо более широкое обсуждение "плюсов/минусов" для любой позиции в документации MongoDB по Data Modeling, которая охватывает различные варианты использования и способы подхода к использованию модели внедрения или ссылки, поддерживаемой методом заполнения.

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