Associations

A Mongoid::Document can have associations to other documents through 3 traditional ActiveRecord-style macros: embeds_one, embeds_many and embedded_in. When setting up associations, one document will act as the root for all other objects in the graph, and all associations will be embedded within that root document in the graph as well as the database itself. Relational associations to documents in other collections are not handled by these macros. Please see the Relational associations below.

Considering the person model from previous examples, associations to other documents would be set up like so:

person.rb:
class Person
  include Mongoid::Document
  field :first_name
  field :last_name
  embeds_one :address
  embeds_many :phones
end
address.rb:
class Address
  include Mongoid::Document
  field :street
  field :city
  field :state
  field :post_code
  embedded_in :person, :inverse_of => :address
end
phone.rb:
class Phone
  include Mongoid::Document
  field :country_code, :type => Integer, :default => 1
  field :number
  embedded_in :person, :inverse_of => :phones
end
Given the above models, an example person saved to the database would have this structure in BSON, where a embeds_one gets embedded as a hash and a embeds_many gets embedded as an array of hashes. Note that the embedded_in macro MUST be defined in order for the embedding to work - don't forget it!
{
  first_name: "Durran",
  last_name: "Jordan",
  address: {
    street: "30 Rockefeller Plaza",
    city: "New York",
    state: "NY",
    post_code: "10112"
  },
  phones: [ { country_code: 1, number: "212-555-1212" } ]
}
Associations may have options associated with them, the most important of which is the required option of inverse_of on a embedded_in association. In order to properly set up the relationships and make sure the object graph is always up to date with any modifications to any object, the embedded_in association must provide this option (and be present itself). The value should be set to the name of the association in its parent object. In addition, a class_name option may be provided if the name of the association differs from a singular or plural form of the document's class name. We can modify the examples above to show what an updated person would look like with the phones association name changed:

person.rb:
class Person
  include Mongoid::Document
  field :first_name
  field :last_name
  embeds_one :address
  embeds_many :phone_numbers, :class_name => "Phone"
end

Building and Creating Associations
Associations can be set directly, appended to, built, or created in certain cases:

embeds_one:
person = Person.new

person.build_address(:street => "Oxford Street")
person.create_address(:street => "Oxford Street")
person.address = Address.new(:street => "Oxford Street")
embeds_many:
person = Person.new

person.phone_numbers.build(:number => "415-555-1212")
person.phone_numbers.create(:number => "415-555-1212")
person.phone_numbers << Phone.new(:number => "415-555-1212")
person.phone_numbers = [ Phone.new(:number => "415-555-1212") ]
embedded_in:
address = Address.new
address.person = Person.new(:first_name => "Mark")

Polymorphic Associations
By default, all embedded_in associations are polymorphic. No matter what name you provide to the macro it will always return the parent object. You may provide the :polymorphic => true option if you like as a "security blanket", but it will actually do nothing extra. An example of this given the above models would be:

address.rb:
class Address
  include Mongoid::Document
  field :street
  field :city
  field :state
  field :post_code
  embedded_in :addressable, :inverse_of => :address
end
In the above example, address.addressable would actually return the parent object, which is the Person.

Association Extensions
Mongoid supports anonymous association extensions, that have access to the proxied target via the target instance variable.

person.rb:
class Person
  include Mongoid::Document
  field :name
  embeds_many :addresses do
    def california
      @target.select { |address| address.state == "CA" }
    end
  end
end
In the above example, person.addresses.california would return only CA addresses.

Relational Associations
Mongoid supports basic relational associations to documents in another collection, or objects that reside in another database. The related object must support ActiveRecord style finders in order for the association to work. The 3 macros provided are references_one, references_many, and referenced_in. When using the macros an id field will be created on the object that is on the referenced_in side of the association, unless using the :stored_as option, which will store ids for the other objects as an array on the defined document and vise-versa. Note that the inverse_of option is a requirement in this case.

person.rb
class Person
  include Mongoid::Document
  references_one :policy
  references_many :prescriptions
  references_many :preferences, :stored_as => :array, :inverse_of => :people
end

class Policy
  include Mongoid::Document
  referenced_in :person
end

class Prescription
  include Mongoid::Document
  referenced_in :person
end

class Preference
  include Mongoid::Document
  references_many :people, :stored_as => :array, :inverse_of => :preferences
end

person = Person.create
policy = Policy.create
prescription = Prescription.create

person.policy = policy
person.prescriptions = [prescription]
Cascading Removals

Similar to ActiveRecord, if you want child relational associations to be deleted when the parent record is deleted, simply supply the :dependent option on the references_one or references_many macro.

class Person
  include Mongoid::Document
  references_one :policy, :dependent => :destroy
  references_many :prescriptions, :dependent => :delete
end

Fork me on GitHub!