Отношения MongoDB: встраивание или ссылка?

Я новичок в MongoDB - исходя из реляционной базы данных. Я хочу создать структуру вопросов с некоторыми комментариями, но я не знаю, какое отношение использовать для комментариев: embed или reference?

Вопрос с некоторыми комментариями, например /qaru.site/..., будет иметь такую ​​структуру:

Question
    title = 'aaa'
    content = bbb'
    comments = ???

Сначала я хочу использовать встроенные комментарии (я думаю, embed рекомендуется в MongoDB), например:

Question
    title = 'aaa'
    content = 'bbb'
    comments = [ { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'} ]

Это ясно, но я беспокоюсь об этом случае: Если я хочу отредактировать указанный комментарий, как мне получить его содержимое и его вопрос? Нет _id, чтобы позволить мне найдите один, и question_ref, чтобы я мог найти его вопрос. (Я так новичок, что не знаю, есть ли способ сделать это без _id и question_ref.)

Нужно ли использовать ref not embed? Затем мне нужно создать новую коллекцию для комментариев?

Ответ 1

Это больше искусство, чем наука. Mongo Documentation on Schemas является хорошей ссылкой, но вот некоторые вещи, которые следует учитывать:

  • Поместите как можно больше

    Радость базы данных Document заключается в том, что она устраняет множество объединений. Ваш первый инстинкт должен состоять в том, чтобы разместить как можно больше в одном документе. Поскольку документы MongoDB имеют структуру и потому что вы можете эффективно запрашивать внутри этой структуры (это означает, что вы можете взять часть документа, который вам нужен, поэтому размер документа не должен вас беспокоить), нет необходимости немедленно нормализовать данные, такие как вы бы в SQL. В частности, любые данные, которые не полезны, кроме его родительского документа, должны быть частью одного и того же документа.

  • Отдельные данные, которые можно отнести из нескольких мест в свою коллекцию.

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

  • Сведения о размере документа

    MongoDB накладывает ограничение на размер 4 МБ (16 МБ с 1,8) для одного документа. В мире GB данных это звучит мало, но это также 30 тысяч твитов или 250 типичных ответов на переполнение стека или 20 мерцающих фотографий. С другой стороны, это гораздо больше информации, чем можно было бы представить в свое время на типичной веб-странице. Сначала рассмотрите, что упростит ваши запросы. Во многих случаях проблема с размером документов будет преждевременной оптимизацией.

  • Сложные структуры данных:

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

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

  • Согласование данных

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

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

Ответ 2

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

Вы можете запросить поддоку: db.question.find({'comments.content' : 'xxx'}).

Это вернет весь документ Вопроса. Чтобы отредактировать указанный комментарий, вам нужно найти комментарий к клиенту, внести изменения и сохранить их обратно в БД.

В общем случае, если ваш документ содержит массив объектов, вы обнаружите, что эти подэлементы должны быть изменены на стороне клиента.

Ответ 3

В целом, вставка хороша, если у вас есть отношения "один-к-одному" или "один ко многим" между объектами, а ссылка хороша, если у вас есть отношения "многие ко многим".

Ответ 4

Я знаю, что это довольно старый, но если вы ищете ответ на вопрос OP о том, как вернуть только указанный комментарий, вы можете использовать $(query) следующим образом:

db.question.update({'comments.content': 'xxx'}, {'comments.$': true})

Ответ 5

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

http://openmymind.net/Multiple-Collections-Versus-Embedded-Documents

Подводя итог:

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

Меньше и/или меньше документов, как правило, подходят для встраивания.

Ответ 6

Ну, я немного опоздал, но все равно хочу поделиться своим способом создания схемы.

У меня есть схемы для всего, что может быть описано словом, как вы делали бы это в классическом ООП.

например.

  • Комментарий
  • Аккаунт
  • Пользователь
  • Блогпост
  • ...

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

Документ

  • Может использоваться как ссылка. (Например, пользователь сделал комментарий → комментарий имеет ссылку "сделано по" пользователю).
  • Это "корень" в вашем приложении. (Например, blogpost → есть страница о блоге)

поддокумент:

  • Может использоваться только один раз/никогда не является ссылкой. (Например, комментарий сохраняется в блоге)
  • Никогда не является "корнем" в вашем приложении. (Комментарий просто отображается на странице блога, но страница все еще о блоге).

Ответ 7

Да, мы можем использовать ссылку в документе. Чтобы заполнить другой документ так же, как sql я joins.In mongo db у них нет объединений для сопоставления одного для многих документов отношений. Вместо этого мы можем использовать заполнить, чтобы выполнить наш сценарий.

var mongoose = require('mongoose')
  , Schema = mongoose.Schema

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

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

Население - это процесс автоматической замены указанных путей в документе документами из других коллекций (ов). Мы можем заполнить единый документ, несколько документов, простой объект, несколько простых объектов или все объекты, возвращаемые из запроса. Рассмотрим несколько примеров.

Лучше вы можете получить дополнительную информацию, пожалуйста, посетите: http://mongoosejs.com/docs/populate.html

Ответ 8

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

Если вы отслеживали количество комментариев и индекс комментария, который хотите изменить, вы можете использовать оператор точки (Пример SOA).

Вы можете сделать f.ex.

db.questions.update(
    {
        "title": "aaa"       
    }, 
    { 
        "comments.0.contents": "new text"
    }
)

(как другой способ редактирования комментариев внутри вопроса)

Ответ 9

Это зависит от использования документа. Когда вы используете документ, если вы всегда используете комментарии, лучший способ использования вложения. Но вы должны учитывать максимальный размер документа (16 МБ).