Связи MongoDB: вставлять или ссылаться?

396

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

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

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? Затем мне нужно создать новую коллекцию для комментариев?

  • 0
    Все объекты Mongo создаются с _ID независимо от того, создаете ли вы поле или нет. Так что технически у каждого комментария все еще будет идентификатор.
  • 19
    Не @RobbieGuilfoyle true-- см stackoverflow.com/a/11263912/347455
Показать ещё 3 комментария
Теги:
embed
reference

9 ответов

684
Лучший ответ

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

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

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

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

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

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

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

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

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

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

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

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

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

  • 1
    Я хотел бы добавить к вопросу OP: Моя модель комментариев содержит имя пользователя и ссылку на его аватар. Каков наилучший подход, учитывая, что пользователь может изменить свое имя / аватар?
  • 0
    Пользователь, я не уверен, что означает «ссылка» в этом контексте. Я думаю, что я бы вставил, если это возможно.
Показать ещё 7 комментариев
33

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

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

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

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

  • 3
    это не будет работать, если два комментария имеют одинаковое содержание. Можно утверждать, что мы могли бы также добавить автора в поисковый запрос, который все равно не работал бы, если бы автор сделал два одинаковых комментария с одинаковым содержанием.
  • 0
    @SteelBrain: если он сохранил индекс комментариев, точечная нотация может помочь. см. stackoverflow.com/a/33284416/1587329
Показать ещё 1 комментарий
21

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

  • 8
    Можете ли вы добавить ссылку ссылку? Благодарю.
16

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

db.question.update({'comments.content': 'xxx'}, {'comments.$': true})
  • 2
    это не будет работать, если два комментария имеют одинаковое содержание. Можно утверждать, что мы могли бы также добавить автора в поисковый запрос, который все равно не работал бы, если бы автор сделал два одинаковых комментария с одинаковым содержанием.
  • 0
    @SteelBrain: Хорошо сыграно, сэр, хорошо сыграно.
15

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

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

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

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

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

  • 5
    Сколько a lot ? 3? 10? 100? Какой large ? 1kb? 1 МБ? 3 поля? 20 полей? Что smaller / fewer ?
  • 1
    Это хороший вопрос, на который у меня нет конкретного ответа. В эту же презентацию был включен слайд с надписью «Документ, включая все встроенные документы и массивы, не может превышать 16 МБ», так что это может быть вашим отсечением или просто пойти на то, что кажется разумным / удобным для вашей конкретной ситуации. В моем текущем проекте большинство встроенных документов предназначены для отношений 1: 1 или 1: многие, где встроенные документы действительно просты.
Показать ещё 1 комментарий
14

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

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

например.

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

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

Документ

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

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

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

Да, мы можем использовать ссылку в документе. Чтобы заполнить другой документ так же, как 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

  • 4
    Mongoose выдаст отдельный запрос для каждого заполненного поля. Это отличается от SQL JOINS, поскольку они выполняются на сервере. Это включает дополнительный трафик между сервером приложений и сервером mongodb. Опять же, вы можете рассмотреть это, когда вы оптимизируете. Тем не менее, ваш ответ по-прежнему правильно.
0

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

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

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

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

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

-2

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню