Overview
Las asociaciones en Mongoid permiten crear relaciones entre modelos. En esta guía, aprenderá a usar asociaciones integradas para almacenar diferentes tipos de documentos en la misma colección. Mongoid admite asociaciones integradas con las siguientes macros:
embeds_oneembeds_manyembedded_inrecursively_embeds_onerecursively_embeds_many
Las siguientes secciones describen cómo emplear estos tipos de asociación.
Embeds One
Para especificar que un modelo de clase contiene un documento incrustado de un tipo de clase diferente, utilice la macro embeds_one en la clase padre y la macro embedded_in en la clase incrustada. El siguiente ejemplo crea una clase Band con una clase Label incrustada:
class Band include Mongoid::Document embeds_one :label end class Label include Mongoid::Document field :name, type: String embedded_in :band end
Mongoid almacena los documentos incrustados con la macro embeds_one en el documento principal como un campo con el mismo nombre que la clase incrustada. Los Label documentos anteriores están almacenados en el documento Band, como se muestra en el siguiente ejemplo:
# Band document { "_id" : ObjectId("..."), "label" : { "_id" : ObjectId("..."), "name" : "Periphery", } }
Puede almacenar el documento incrustado con un nombre diferente utilizando la opción store_as, como se muestra en el siguiente ejemplo:
class Band include Mongoid::Document embeds_one :label, store_as: "record_label" end
Incorpora Muchos
Para especificar que un modelo de clase contiene varios documentos incrustados de un tipo de clase diferente, use la macro embeds_many en la clase principal y la macro embedded_in en la clase integrada. El siguiente ejemplo crea una clase Band con varios documentos incrustados del tipo Album:
class Band include Mongoid::Document embeds_many :albums end class Album include Mongoid::Document field :name, type: String embedded_in :band end
Mongoid almacena los documentos embebidos con la macro embeds_many en el documento principal como un campo de arreglo con el mismo nombre que la clase embebida. Los documentos Album anteriores se almacenan en el documento Band, como se muestra en el siguiente ejemplo:
{ "_id" : ObjectId("..."), "albums" : [ { "_id" : ObjectId("..."), "name" : "Omega", } ] }
Puede almacenar el documento incrustado con un nombre diferente utilizando la opción store_as, como se muestra en el siguiente ejemplo:
class Band include Mongoid::Document embeds_many :albums, store_as: "records" end
Embedding recursivo
Puedes insertar uno o más documentos del mismo tipo en una clase principal utilizando las macros recursively_embeds_one y recursively_embeds_many. Ambas macros proporcionan acccesores para los documentos principal e hijo a través de un método parent_* y un método child_*, donde * representa el nombre de la clase. El siguiente ejemplo crea una clase Band que inserta recursivamente múltiples otros documentos Band para representar múltiples nombres de bandas:
class Band include Mongoid::Document field :name, type: String recursively_embeds_many end
Puedes acceder a los documentos padre e hijo mediante los métodos parent_band y child_band, como se muestra en el siguiente ejemplo:
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
Query de asociaciones integradas
Se pueden acceder a los documentos incrustados al consultar la colección de la clase superior utilizando la notación de puntos.
El siguiente ejemplo utiliza notación de puntos para query documentos tipo Tour incrustados en una clase Band. El query devuelve documentos que tienen un valor de tours.year de 2000 o superior:
Band.where('tours.year' => {'$gte' => 2000})
Puede utilizar el método de proyección pluck para recuperar documentos incrustados sin recuperar sus documentos parentales asociados, como se muestra en el siguiente ejemplo:
# Get awards for bands that have toured since 2000 Band.where('tours.year' => {'$gte' => 2000}).pluck(:awards)
Puedes usar los métodos de query de Mongoid para realizar coincidencias incrustadas. Esto te permite consultar asociaciones incrustadas de documentos que ya han sido cargados en la aplicación. Mongoid implementa la coincidencia embebida sin enviar consultas al servidor.
Los siguientes operadores del query son compatibles con la coincidencia incrustada:
El siguiente ejemplo query el campo tours incrustado de un documento Band cargado utilizando el operador de comparación $gte:
band = Band.where(name: 'Astral Projection').first tours = band.tours.where(year: {'$gte' => 2000})
La coincidencia integrada en documentos cargados tiene las siguientes limitaciones conocidas:
La coincidencia incrustada no está implementada para las siguientes funcionalidades:
Operadores que ejecutan código JavaScript, como $where
Operadores que se implementan a través de otras funcionalidades del servidor, como $expr y $jsonSchema
Mongoid expande los argumentos
Rangea hashes con las condiciones$gtey$lte. Esto puede generar consultas no válidas en algunos casos y provocar una excepciónInvalidQuery.Con el operador
$regex, no puedes especificar un objeto de expresión regular como patrón a la vez que proporcionas opciones en el campo$options. Solo puedes proporcionar opciones si el patrón de expresión regular es un string.
Omitir campos _id
Por defecto, Mongoid añade un campo _id a los documentos incrustados. Se puede omitir este campo de los documentos incrustados mediante la especificación explícita del campo _id en el modelo y la omisión del valor por defecto. El siguiente ejemplo ordena a Mongoid no agregar un campo _id a la clase Albums:
class Album include Mongoid::Document field :name, type: String field :_id, type: Object embedded_in :band end
En la clase Albums anterior, el campo _id no se agrega automáticamente. Sin un valor por defecto, Mongoid no almacena el valor en la base de datos a menos que proporciones uno en tu modelo.
Borrar asociaciones incrustadas
Puede eliminar documentos secundarios de embeds_many asociaciones utilizando uno de los siguientes métodos:
cleardelete_alldestroy_all
El método clear utiliza el operador $unset para remover toda una asociación incrustada del documento principal. El método clear no ejecuta ninguna función de retorno de destroy. El siguiente ejemplo usa el método clear para remover todas las asociaciones incrustadas de la clase Band:
band = Band.find(...) band.tours.clear
El método delete_all utiliza el operador $pullAll para remover documentos en una asociación embebida. delete_all carga la asociación si aún no se ha cargado, y entonces solo remueve los documentos que existen en la aplicación. El método delete_all no ejecuta ninguna función de retorno de destroy. El siguiente ejemplo utiliza el método delete_all para remover todos los documentos Album integrados de la clase Band:
band = Band.find(...) band.tours.delete_all
El método destroy_all también utiliza el operador operador $pullAll para eliminar documentos en una asociación embebida. También ejecuta cualquier destroy función de retorno que se haya definido en los documentos asociados. El siguiente ejemplo utiliza el método destroy_all para remover todos los documentos Album embebidos de la clase Band:
band = Band.find(...) band.tours.destroy_all