Overview
Las asociaciones en Mongoid permiten crear relaciones entre modelos. En esta guía, aprenderá cómo las asociaciones referenciadas permiten crear una relación entre dos modelos donde uno hace referencia al otro. Mongoid admite los siguientes tipos de asociaciones referenciadas:
has_onehas_manybelongs_tohas_and_belongs_to_many
Las siguientes secciones describen cómo utilizar cada uno de estos tipos de asociación.
Tiene uno
Puede utilizar la macro has_one para declarar que los documentos representados por una clase también contienen un documento representado por una clase hija independiente. El siguiente ejemplo crea una clase Band con una relación has_one a una clase Studio:
class Band include Mongoid::Document has_one :studio end
Cuando declaras una asociación has_one, la clase hijo también debe usar la asociación belongs_to que referencia a la clase padre. El siguiente ejemplo muestra la clase Studio referenciada en la clase anterior Band:
class Studio include Mongoid::Document belongs_to :band end
Para obtener más información sobre la macro belongs_to, consulta la Pertenece a la sección.
Puede usar validaciones para asegurarse de que la clase secundaria esté presente en su clase principal, como se muestra en el siguiente ejemplo:
class Band include Mongoid::Document has_one :studio validates_presence_of :studio end
Para obtener más información sobre las validaciones en Mongoid, consulte el Validations guide.
Contiene muchos
Puedes usar la macro has_many para declarar que los documentos representados por una clase contienen múltiples documentos secundarios representados por otra clase. El siguiente ejemplo crea una clase Band con una relación has_many a una clase Members:
class Band include Mongoid::Document has_many :members end
Cuando declaras una asociación has_many, la clase hijo también debe usar la asociación belongs_to que referencia a la clase padre. El siguiente ejemplo muestra la clase Member referenciada en la clase anterior Band:
class Member include Mongoid::Document belongs_to :band end
Para obtener más información sobre la macro belongs_to, consulta la sección Pertenece a.
Puede usar validaciones para asegurarse de que la clase secundaria esté presente en su clase principal, como se muestra en el siguiente ejemplo:
class Band include Mongoid::Document has_many :members validates_presence_of :members end
Para aprender más sobre validaciones en Mongoid, consulta la guía de Validaciones.
Recuperar información de la asociación
Puedes utilizar el método any? en una asociación has_many para determinar si la asociación contiene algún documento sin recuperar el conjunto completo de documentos de la base de datos.
El siguiente ejemplo utiliza el método any? para determinar si los documentos de la clase Band contienen algún documento Members:
band = Band.first band.members.any?
También puedes utilizar el método any? con un filtro para encontrar documentos que cumplan con un criterio determinado, como se muestra en el siguiente ejemplo:
band = Band.first band.members.any? { |member| member.instrument == 'piano' }
Puedes proporcionar un nombre de clase al método any? para filtrar los resultados por el nombre de la clase. Esto es útil para asociaciones polimórficas:
class Drummer < Member end band = Band.first band.members.any?(Drummer)
Nota
Una vez que los datos de la clase asociada se cargan a Mongoid, las siguientes llamadas al método any? no query la base de datos. En su lugar, Mongoid utiliza los datos que ya están cargados en la memoria.
También puede llamar al método exists? para determinar si hay algún documento persistente en la asociación. El método exists? siempre consulta la base de datos y solo verifica los documentos que han sido guardados en la base de datos. El método exists? no permite filtrar ni acepta ningún argumento.
El siguiente ejemplo usa el método exists? para determinar si existen documentos Members persistidos en la clase Band:
band = Band.create! # Member is not persisted. band.members.build band.members.exists? # Outputs: false # Persist the member band.members.map(&:save!) band.members.exists? # Outputs: true
Pertenece a
Utiliza la macro belongs_to para declarar que un documento representado por una clase es hijo de un documento representado por otra clase. Por defecto, el campo _id de la clase principal se almacena en la clase secundaria. El siguiente ejemplo crea una clase Members con una asociación belongs_to a una clase Band:
class Members include Mongoid::Document belongs_to :band end
Puedes permitir que Mongoid persista documentos en la base de datos sin almacenar el _id de la clase padre asociada estableciendo la opción optional en true, como se muestra en el siguiente ejemplo:
class Members include Mongoid::Document belongs_to :band, optional: true end
Tip
Puede cambiar globalmente el comportamiento por defecto de la asociación belongs_to para que no requiera su clase principal configurando la opción de configuración belongs_to_required_by_default en false en la configuración de su aplicación.
Puedes especificar una asociación de belongs_to en una clase secundaria sin especificar una asociación de has_one ni de has_many en la clase principal. Al hacerlo así, no se puede acceder a los campos del documento secundario desde la clase principal, pero sí se puede acceder a los campos principales que se almacenan en la clase secundaria, como el campo _id del principal. En el siguiente ejemplo, la clase Band no puede acceder a la clase Members, pero la clase Members sí puede acceder a la clase Band:
class Band include Mongoid::Document end class Members include Mongoid::Document belongs_to :band end
Para mayor claridad, de manera opcional, puedes establecer la opción inverse_of en nil para indicar que la clase padre no contiene una asociación has_one o has_many con la clase hija, como se muestra en el siguiente ejemplo:
class Band include Mongoid::Document end class Members include Mongoid::Document belongs_to :band, inverse_of: nil end
Tiene y Pertenece a Muchos
Utilice el macro has_and_belongs_to_many para declarar que un modelo de clase contiene una relación de muchos a muchos con otra clase. En una relación de muchos a muchos, cada documento de una clase se puede asociar con varios documentos en otra clase. El siguiente ejemplo crea una clase Band con una relación has_and_belongs_to_many a una clase Members. Un documento Band puede hacer referencia a varios documentos Members, y un documento Members puede hacer referencia a varios documentos Band.
class Band include Mongoid::Document has_and_belongs_to_many :members end class Members include Mongoid::Document has_and_belongs_to_many :bands end
Cuando declaras una asociación has_and_belongs_to_many, ambas instancias del modelo almacenan una lista de los valores _id del documento asociado. Puedes establecer la opción inverse_of en nil para almacenar los valores _id del documento asociado solo en una de las instancias del modelo. El siguiente ejemplo solicita a Mongoid que almacene los valores _id del documento asociado solo en la clase Band:
class Band include Mongoid::Document has_and_belongs_to_many :tags, inverse_of: nil end class Tag include Mongoid::Document end
Tip
Cuando actualizas un documento que tiene una asociación has_and_belongs_to_many, Mongoid establece el campo updated_at del documento actualizado, pero no establece el campo updated_at de los documentos asociados.
Query asociaciones referenciadas
Puede utilizar un pipeline de agregación para hacer query documentos en asociaciones referenciadas. El pipeline de agregación te permite crear consultas en varias colecciones y manipular los datos en un formato específico. Para obtener más información sobre el uso del pipeline de agregación, consulta la guía de Agregación.
Para simples queries, puede query la asociación directamente. Cuando query directamente en una colección, solo puedes query sobre los campos y valores que se encuentran en la colección en sí. No puedes consultar directamente en las colecciones asociadas a la que estás consultando.
Por ejemplo, consideremos las siguientes clases Band y Tour:
class Band include Mongoid::Document has_many :tours field :name, type: String end class Tour include Mongoid::Document belongs_to :band field :year, type: Integer end
El siguiente ejemplo query la clase Tour para los documentos que tienen un valor de year de 2000 o superior y guarda el band_id de esos documentos. Luego query la clase Band para obtener documentos que tienen esos valores de band_id.
band_ids = Tour.where(year: {'$gte' => 2000}).pluck(:band_id) bands = Band.find(band_ids)