2016-07-01 2 views
3

Я хотел бы узнать, возможно ли (или даже правильно) использовать встроенные документы в качестве ссылки в других документах.Данные Spring MongoDB - Встроенный документ как ссылка в другом документе

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

Например:

Пользователь

{ 
    _id: ObjectId("4fed0591d17011868cf9c982"), 
    _class: "User" 
    ... 
    addresses: [ { 
     _id: ObjectId("87KJbk87gjgjjygREewakj86"), 
     _class: "Address", 
     ... 
    } ] 
} 

Заказать

{ 
    _id: ObjectId("gdh60591d123487658cf9c982"), 
    _class: "Order", 
    ... 
    address: ObjectId("87KJbk87gjgjjygREewakj86") 
} 

ответ

4

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

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

Без знания всей вашей модели домена адрес кажется идеальным кандидатом для объекта значения. Не поддерживайте коллекцию Address, вставьте ее в объект пользователя. В Order вы можете либо сделать ссылку на пользователя, что дает вам неявно адресный объект и может иметь смысл, так как заказ сделан пользователем.

Но ... Я рекомендую вам полностью вставлять адрес в заказ. Во-первых, это быстрее, поскольку вам не нужно разрешать ссылку. Во-вторых, адрес в отправленных заказах никогда не должен меняться! Рассмотрите заказы прошлого года. Если вы держите ссылку на адрес, вы потеряете информацию о том, какой адрес они были отправлены, как только пользователь изменит свой адрес.

Рекомендация: Всегда делайте снимок адреса и вставляйте его в Order. Сохраните идентификатор MongoDB пользователя в виде обычной строки (no @DBRef) в разделе «Заказ». Если пользователь должен изменить свой адрес, вы можете сделать запрос для всех не отгруженных заказов этого пользователя и изменить адрес.

+1

Спасибо за ваш комментарий! –

0

Поскольку я не получил никакого ответа я размещу здесь, как я это сделал. Если у вас есть лучшее решение, я счастлив здесь.

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

Пользователь

{ 
    _id: ObjectId("4fed0591d17011868cf9c982"), 
    _class: "User" 
    ... 
    addresses: [ { 
     "$ref" : "addresses", 
     "$id" : ObjectId("87KJbk87gjgjjygREewakj86") 
    } ] 
} 

Адрес

{ 
    _id: ObjectId("87KJbk87gjgjjygREewakj86"), 
    ... 
} 

Заказать

{ 
    _id: ObjectId("gdh60591d123487658cf9c9867"), 
    _class: "Order", 
    ... 
    address: { 
     "$ref" : "addresses", 
     "$id" : ObjectId("87KJbk87gjgjjygREewakj86") 
    } 
} 
1

Поскольку вы спросили, верно ли это, я бы сказал, мягко: «Нет». По крайней мере, не типично.

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

Вы можете ссылаться на встроенный пользовательский адрес в объекте заказа, просто не так, как вы могли бы подумать! Если вы сохранили идентификатор пользователя в заказе (он должен быть уже там, если Order принадлежит пользователю), вы просто используете user.address вместо копирования экземпляра адреса, как вы это сделали.

АЛЬТЕРНАТИВА

Я надеюсь проиллюстрировать лучший подход к моделированию домен ...

Более общий подход заключается в создании экземпляра нового объекта заказа, используя адрес пользователя по умолчанию «судно на «адрес для заказа», но при необходимости разрешить пользователю переопределять адрес доставки. Теоретически каждый заказ может иметь разные «корабль к» адресу.

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

КОММЕНТАРИЙ

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

Предположите, что ваш адрес в прошлом году был в Испании, и у вас был приказ № 1 показать Испанию, когда вы запустили отчет о Заказе в прошлом году. Представьте себе, если ваш адрес в этом году в настоящее время является Португалией, а в Приказе № 1 теперь отображается Португалия в том же отчете. Это было бы неверно.

BTW: @Matt дал вам подсказку, что с точки зрения «проблемной области» вы, скорее всего, не захотите моделировать ее, как есть. Я просто разрабатываю ...

Смежные вопросы