Переделал этот ответ, поскольку исходный ответ неверно перевернул отношение из-за неправильного прочтения.
issue = {code: "asdf-11", заголовок: "asdf", репортер: {username: "qwer", роль: "manager"}}
Относительно того, является ли вложение какой-либо важной информации о пользователе (создателе) билета разумным решением или нет, зависит от особенностей системы.
Предоставляете ли вы этим пользователям возможность войти и сообщить о найденных проблемах? Если это так, то, вероятно, вы захотите включить это отношение в коллекцию пользователей.
С другой стороны, если это не так, вы могли бы легко избежать этой схемы. Единственная проблема, которую я вижу здесь, это то, что если вы хотите связаться с репортером, и его должность изменилась, это несколько неловко; однако это настоящая дилемма, а не проблема базы данных.
Поскольку поддокумент представляет собой однозначное отношение к репортеру, вы также не должны испытывать проблем фрагментации, упомянутых в моем первоначальном ответе.
Существует одна вопиющая проблема с этой схемой, которая заключается в дублировании изменения повторяющихся данных (нормализованные формы).
Давайте рассмотрим пример. Представьте, что вы столкнулись с реальной дилеммой, о которой я говорил ранее, и пользователь с именем Nigel
хочет, чтобы его роль отныне отражала его новую должность. Это означает, что вам нужно обновить все строки, где Nigel
является репортером, и изменить его role
на эту новую позицию. Это может быть длительным и ресурсоемким запросом для MongoDB.
Снова противореча самому себе: если бы у вас было всего 100 билетов (что-то управляемое) на пользователя, тогда операция обновления, скорее всего, была бы не слишком плохой и, на самом деле, легко управляемой для базы данных; плюс из-за отсутствия перемещения (надеюсь) документов, это будет полностью обновленное место.
Так что, должно ли это быть встроено или нет, сильно зависит от ваших запросов, документов и т. Д., Однако, я бы сказал, что эта схема не очень хорошая идея; особенно из-за дублирования изменяющихся данных во многих корневых документах. Технически, да, вы могли бы сойти с рук, но я бы не стал пытаться.
Я бы вместо этого разделил их.
Если в документе есть объекты (поддокументы), могу ли я обновить их все в одном запросе?
Так же, как стиль отношений в моем первоначальном ответе, да и легко.
Например, давайте обновим роль с Nigel
до MD
(как уже упоминалось ранее) и изменим статус заявки на выполненный:
db.tickets.update({'reporter.username':'Nigel'},{$set:{'reporter.role':'MD', status: 'completed'}})
Таким образом, одна схема документа облегчает CRUD в этом случае.
Следует отметить, что, исходя из вашего английского, вы не можете использовать позиционный оператор для обновления всех вложенных документов в корневом документе. Вместо этого он обновит только первый найденный.
Опять же, надеюсь, это имеет смысл, и я ничего не упустил. НТН
Оригинальный ответ
здесь у меня есть пользователь, связанный с проблемой). Должен ли я создать другой документ «пользователь» и ссылаться на него в «выпускном» документе по его идентификатору (как в реляционных базах данных), или я должен оставить все данные пользователя в поддокументе?
Это серьезный вопрос, и для его продолжения требуются некоторые базовые знания.
Первое, что нужно учитывать, это размер проблемы:
issue = {code:"asdf-11", title:"asdf", reporter:{username:"qwer", role:"manager"}}
не очень большой, и, поскольку вам больше не нужна информация reporter
(которая будет в корневом документе), она может быть меньше, однако проблемы никогда не бывают такими простыми. Если вы посмотрите на MongoDB JIRA, например: https://jira.mongodb.org/browse/SERVER-9548 (как случайная страница, подтверждающая мою точку зрения), то содержание «тикета» может быть весьма значительным.
Единственный способ получить реальную выгоду от встраивания билетов - это если вы сможете хранить ВСЕ пользовательскую информацию в одном 16-мегабайтном блоке непрерывного хранения, который является максимальным размером документа BSON (как установлено * 1062). * В настоящее время).
Не думаю, что вы сможете хранить все билеты под одним пользователем.
Даже если вы захотите сжать билет, может быть, до кода, заголовка и описания, вы все равно можете страдать от проблемы «швейцарского сыра», вызванной регулярными обновлениями и изменениями в документах в MongoDB, как всегда: http://www.10gen.com/presentations/storage-engine-internals хорошая ссылка на то, что я имею в виду.
Обычно вы наблюдаете эту проблему, когда пользователи добавляют несколько заявок в свой корневой пользовательский документ. Сами билеты тоже будут меняться, но, возможно, не радикально или часто.
Конечно, вы можете немного исправить эту проблему, используя степень распределения 2 размеров: http://docs.mongodb.org/manual/reference/command/collMod/#usePowerOf2Sizes, которая будет делать то же, что и на банке.
Хорошо, гипотетически, если бы у вас были только code
и title
, тогда да, вы могли бы хранить заявки как поддокументы у пользователя root без особых проблем, однако это то, что сводится к специфике, что правопреемник не упомянул.
Если в документе есть объекты (поддокументы), могу ли я обновить их все в одном запросе?
Да, довольно легко. Это одна вещь, которая становится легче с встраиванием. Вы можете использовать запрос как:
db.users.update({user_id:uid,'tickets.code':'asdf-1'}, {$set:{'tickets.$.title':'Oh NOES'}})
Однако следует отметить, что вы можете обновлять только ОДИН поддокумент за один раз, используя позиционный оператор. Таким образом, это означает, что вы не можете в одной атомарной операции обновить все даты заявок на одного пользователя до 5 дней в будущем.
Что касается добавления нового билета, это довольно просто:
db.users.update({user_id:uid},{$push:{tickets:{code:asdf-1,title:"Whoop"}}})
Так что да, вы можете довольно просто, в зависимости от ваших запросов, обновить данные всего пользователя за один вызов.
Это был довольно длинный ответ, так что, надеюсь, я ничего не пропустил, надеюсь, это поможет.