Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
Click here >
Docs Menu
Docs Home
/ /

Embedded Associations

Associations in Mongoid allow you to create relationships between models. In this guide, you can learn how to use embedded associations to store different types of documents in the same collection. Mongoid supports embedded associations with the following macros:

  • embeds_one

  • embeds_many

  • embedded_in

  • recursively_embeds_one

  • recursively_embeds_many

The following sections describe how to use these association types.

To specify that a class model contains an embedded document of a different class type, use the embeds_one macro in the parent class and the embedded_in macro in the embedded class. The following example creates a Band class with an embedded Label class:

class Band
include Mongoid::Document
embeds_one :label
end
class Label
include Mongoid::Document
field :name, type: String
embedded_in :band
end

Mongoid stores documents embedded with the embeds_one macro in the parent document as a field with the same name as the embedded class. The preceding Label documents are stored in the Band document, as shown in the following example:

# Band document
{
"_id" : ObjectId("..."),
"label" : {
"_id" : ObjectId("..."),
"name" : "Periphery",
}
}

You can store the embedded document with a different name by using the store_as option, as shown in the following example:

class Band
include Mongoid::Document
embeds_one :label, store_as: "record_label"
end

To specify that a class model contains multiple embedded documents of a different class type, use the embeds_many macro in the parent class and the embedded_in macro in the embedded class. The following example creates a Band class with multiple embedded Album type documents:

class Band
include Mongoid::Document
embeds_many :albums
end
class Album
include Mongoid::Document
field :name, type: String
embedded_in :band
end

Mongoid stores documents embedded with the embeds_many macro in the parent document as an array field with the same name as the embedded class. The preceding Album documents are stored in the Band document, as shown in the following example:

{
"_id" : ObjectId("..."),
"albums" : [
{
"_id" : ObjectId("..."),
"name" : "Omega",
}
]
}

You can store the embedded document with a different name by using the store_as option, as shown in the following example:

class Band
include Mongoid::Document
embeds_many :albums, store_as: "records"
end

You can embed one or more documents of the same type into a parent class by using the recursively_embeds_one and recursively_embeds_many macros. Both macros provide accessors for the parent and child documents through a parent_* method and a child_* method, where * represents the name of the class. The following example creates a Band class that recursively embeds multiple other Band documents to represent multiple band names:

class Band
include Mongoid::Document
field :name, type: String
recursively_embeds_many
end

You can access the parent and child documents through the parent_band and child_band methods, as shown in the following example:

root = Band.new(name: "Linkin Park")
# Add child bands
child_one = root.child_band.build(name: "Lincoln Park")
child_two = root.child_band.build(name: "Xero")
# Access parent band
child_one.parent_band
# Outputs: root

You can access embedded documents when querying the collection of the parent class by using dot notation.

The following example uses dot notation to query Tour type documents that are embedded in a Band class. The query returns documents that have a tours.year value of 2000 or greater:

Band.where('tours.year' => {'$gte' => 2000})

You can use the pluck projection method to retrieve embedded documents without retrieving their associated parent documents, as shown in the following example:

# Get awards for bands that have toured since 2000
Band.where('tours.year' => {'$gte' => 2000}).pluck(:awards)

You can use Mongoid query methods to perform embedded matching, which allows you to query on embedded associations of documents that are already loaded in the application. Mongoid implements embedded matching without sending queries to the server.

The following query operators are supported with embedded matching:

  • Comparison operators

  • Logical operators

  • Array query operators

  • $exists

  • $mod

  • $type

  • $regex

  • Bitwise operators

The following example queries the embedded tours field of a loaded Band document by using the $gte comparison operator:

band = Band.where(name: 'Astral Projection').first
tours = band.tours.where(year: {'$gte' => 2000})

Embedded matching on loaded documents has the following known limitations:

  • Embedded matching is not implemented for the following features:

    • Text querying

    • Geospatial queries

    • Operators that execute JavaScript code, such as $where

    • Operators that are implemented through other server functionality, such as $expr and $jsonSchema

  • Mongoid expands Range arguments to hashes with $gte and $lte conditions. This can lead to invalid queries in some cases and raises a an InvalidQuery exception.

  • With the $regex operator, you cannot specify a regular expression object as a pattern while also providing options to the $options field. You can only provide options if the regular expression pattern is a string.

By default, Mongoid adds an _id field to embedded documents. You can omit this field from embedded documents by explicitly specifying the _id field in your model and omitting the default value. The following example instructs Mongoid not to add an _id field to the Albums class:

class Album
include Mongoid::Document
field :name, type: String
field :_id, type: Object
embedded_in :band
end

In the preceding Albums class, the _id field is not automatically added. Without a default value, Mongoid does not store the value in the database unless you provide one in your model.

You can delete child documents from embeds_many associations by using one of the following methods:

  • clear

  • delete_all

  • destroy_all

The clear method uses the $unset operator operator to remove an entire embedded association from the parent document. The clear method does not run any destroy callbacks. The following example uses the clear method to remove all embedded associations from the Band class:

band = Band.find(...)
band.tours.clear

The delete_all method uses the $pullAll operator operator to remove documents in an embedded association. delete_all loads the association if it has not yet been loaded, then only removes the documents that exist in the application. The delete_all method does not run any destroy callbacks. The following example uses the delete_all method to remove all embedded Album documents from the Band class:

band = Band.find(...)
band.tours.delete_all

The destroy_all method also uses the $pullAll operator operator to remove documents in an embedded association. It also runs any destroy callbacks that are defined on the associated documents. The following example uses the destroy_all method to remove all embedded Album documents from the Band class:

band = Band.find(...)
band.tours.destroy_all

Back

Referenced Associations

On this page