colllin
colllin

Reputation: 9789

How to link to an EmbeddedDocument in MongoMapper?

I'm not very confident about this schema design (suggestions welcome), but I have two collections:

and each of them contains embedded documents:

The class definitions are below, but first, the question. When I create a Business and add an Event, everything looks fine. When I create a Customer and add a Registration, everything looks fine. At this point, I can do:

ruby-1.9.2-p180 :380 > customer1.registrations.first.customer
 => #<Customer _id: BSON::ObjectId('4eb22a5bbae7a01331000019'), business_id: BSON::ObjectId('4eb215a9bae7a01331000001'), registrations: nil> 

Perfect! But then... I add the Registration to the Event using event1.registrations << registration1, and now event1 has a different customer reference depending on whether I access it through the Event or through the Customer:

ruby-1.9.2-p180 :444 > customer1.registrations.first.customer
 => #<Customer _id: BSON::ObjectId('4eb22a5bbae7a01331000019'), business_id: BSON::ObjectId('4eb215a9bae7a01331000001'), posts: nil> 

ruby-1.9.2-p180 :445 > business1.events.first.registrations.first.customer
 => #<Event _id: BSON::ObjectId('4eb21ab2bae7a0133100000f'), business_id: BSON::ObjectId('4eb215a9bae7a01331000001'), posts: nil> 

ruby-1.9.2-p180 :446 > business1.events.first.registrations.first == customer1.registrations.first
 => true 

Not perfect.... my best guess is that duplicates of registration1 have been embedded in both customer1 and event1? What I wanted was links between the Event and its many Registrations (which are owned and embedded in Customers). Is that possible with this schema?

This is what my models look like. They all have additional (and irrelevant) keys that are not displayed:

class Business
  include MongoMapper::Document

  many :events
  many :customers
end

class Event
  include MongoMapper::EmbeddedDocument

  embedded_in :business

  many :registrations
end

class Customer
  include MongoMapper::Document

  belongs_to :business
  key :business_id, ObjectId

  many :registrations
end

class Registration
  include MongoMapper::EmbeddedDocument

  embedded_in :customer

  belongs_to :event
  key :event_id, ObjectId
end

Upvotes: 1

Views: 623

Answers (1)

Brian Hempel
Brian Hempel

Reputation: 9094

Yep. Registration is a MongoMapper::EmbeddedDocument so it's always embedded. That means because both Customer and Event have many :registrations, different registration objects will be embedded in each.

In MongoMapper, the embedded_in :customer just alias a customer method to return the document's parent. It's just a fancier way of calling _parent_document. That's why your event's registration's customer is an event object. (See source here).

The rule of thumb is to only embed when the child will always be used in context of its parent.

Upvotes: 1

Related Questions