Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /

Implementar la herencia de modelos

En esta guía, puedes aprender cómo implementar la herencia en tus modelos de Mongoid. La herencia permite aplicar las características de una clase "principal" a una o más clases "secundarias".

Mongoid admite la herencia en documentos de nivel superior y documentos incrustados. Cuando una clase modelo hija hereda de una clase padre, Mongoid copia los campos, asociaciones, validaciones y ámbitos de la clase padre a la clase hija.

Al crear una clase de modelo secundario, use el < Carácter para implementar la herencia de una clase padre especificada. Las siguientes clases modelo muestran cómo crear clases padre e hijas entre los modelos Person, Employee y Manager:

class Person
include Mongoid::Document
field :name, type: String
end
class Employee < Person
field :company, type: String
field :tenure, type: Integer
scope :new_hire, ->{ where(:tenure.lt => 1) }
end
class Manager < Employee
end

Mongoid guarda instancias de Person, Employee y Manager en la colección people. Mongoid establece el campo discriminador _type al nombre de la clase del modelo en los documentos para garantizar que los documentos se devuelvan como los tipos esperados cuando se realicen operaciones de lectura.

También se puede implementar un patrón de herencia en asociaciones incrustadas. De forma similar al comportamiento de las clases de modelo de nivel superior, Mongoid establece el campo discriminador _type en los documentos incrustados según la clase de modelo utilizada para crearlos.

El siguiente ejemplo añade una asociación incrustada al modelo Person y crea modelos padre e hijo para la clase anidada Info:

class Person
include Mongoid::Document
field :name, type: String
embeds_many :infos
end
...
class Info
include Mongoid::Document
field :active, type: Boolean
embedded_in :person
end
class Phone < Info
field :value, type: Float
field :country, type: String
end
class Email < Info
field :value, type: String
field :category, type: String
end

Cuando se realiza una query en una clase de modelo hijo, la query devuelve solo documentos en los que el valor del campo _type coincide con la clase consultada o con otras clases hijas. Por ejemplo, si realizas una query en la clase Employee, la query devolverá documentos de la colección people en los que el valor _type sea "Employee" o "Manager". Todos los demás valores de discriminador se consideran como instancias de la clase principal Person.

Al consultar en una clase principal como Person, Mongoid devuelve documentos que cumplen alguno de los siguientes criterios:

  • El valor del discriminador es el nombre de la clase principal o de cualquiera de las clases secundarias. Por ejemplo, "Person", "Employee" o "Manager".

  • No tiene un valor de discriminador.

  • El valor del discriminador no corresponde ni al padre ni a ninguna de sus clases hijas. Por ejemplo, "Director" o "Specialist".

Puedes cambiar la clave discriminatoria del nombre de campo por defecto _type por cualquiera de las siguientes razones:

  • Optimización: puedes seleccionar una clave más corta como _t.

  • Coherencia con un sistema existente: Es posible que esté utilizando un sistema o conjunto de datos existente que tiene claves predefinidas.

Puedes cambiar la clave discriminatoria a nivel de clase o a nivel global. Para cambiar la clave discriminatoria a nivel de clase, puedes establecer el nombre de clave personalizado en la clase principal utilizando el método discriminator_key.

El siguiente ejemplo demuestra cómo establecer una clave discriminadora personalizada al definir una clase de modelo:

class Person
include Mongoid::Document
field :name, type: String
self.discriminator_key = "sub_type"
end

Cuando cree una instancia de Person o de cualquiera de sus subclases, Mongoid agrega el campo sub_type a los documentos en MongoDB.

Nota

Puede cambiar la clave del discriminador solo en la clase principal. Mongoid genera un error si se establece una clave personalizada en cualquier clase secundaria.

Si cambias la clave de discriminador después de definir una clase hija, Mongoid agrega el nuevo campo clave, pero el campo anterior permanece sin cambios. Por ejemplo, supón que agregas el siguiente código a tu aplicación después de definir tus clases de modelos:

Person.discriminator_key = "sub_type"

En este caso, cuando se crea una instancia de una clase secundaria como Employee, Mongoid agrega los campos sub_type y _type al documento.

También puedes cambiar la clave discriminadora a nivel global, para que todas las clases utilicen la clave especificada en lugar del campo _type.

Puedes establecer una clave global añadiendo el siguiente código a tu aplicación antes de definir cualquier clase de modelo:

Mongoid.discriminator_key = "sub_type"

Todas las clases utilizan sub_type como clave discriminadora y no incluyen el campo _type.

Nota

Se debe establecer la clave discriminadora a nivel global antes de definir cualquier clase hija para que las clases utilicen ese valor global. Si estableces la clave global después de definir clases hijas, tus documentos guardados contienen el campo por defecto _type.

Puedes personalizar el valor que Mongoid establece como valor discriminador en MongoDB. Use el método discriminator_value al definir una clase para personalizar el valor del discriminador, como se muestra en el siguiente ejemplo:

class Employee
include Mongoid::Document
field :company, type: String
self.discriminator_value = "Worker"
end

Cuando se crea una instancia de Employee, el campo discriminador _type del documento tiene un valor de "Worker" en lugar del nombre de la clase.

Nota

Debido a que la personalización del valor del discriminador se declara en las clases secundarias, debe cargar las clases secundarias recuperadas por una consulta antes de enviar esa consulta.

En el ejemplo anterior, la definición de clase Employee debe cargarse antes de realizar una query en Person si los documentos que se devuelven incluyen instancias de Employee. La carga automática no puede resolver el valor del discriminador "Worker" para devolver documentos como instancias de Employee.

Puede crear cualquier tipo de clase padre o clase hija en una asociación incrustada mediante asignación o usando los métodos build y create. Puede pasar la clase de modelo deseada como segundo parámetro a los métodos build y create para indicar a Mongoid que cree esa instancia específica como un documento incrustado.

El siguiente código crea una instancia de Employee y luego demuestra cómo agregar documentos incrustados utilizando los diferentes métodos de creación:

# Creates a new Employee instance
e = Employee.create(
name: "Lance Huang",
company: "XYZ Communications",
tenure: 2
)
# Builds an Info object
e.infos.build({ active: true })
# Builds a Phone object
e.infos.build(
{ active: true, value: 1239007777, country: "USA" },
Phone
)
# Creates an Email object
e.infos.create(
{ active: true, value: "l.huang@company.com", category: "work" },
Email
)
# Creates and assigns an Email object
p = Email.new(active: false, value: "lanceh11@mymail.com", category: "personal" )
e.infos << p
# Saves the Employee instance to database
e.save

El siguiente documento se almacena en la base de datos people:

{
"_id": {...},
"name": "Lance Huang",
"company": "XYZ Communications",
"tenure": 2,
"_type": "Employee",
"infos": [
{
"_id": {...},
"active": true,
"value": "l.huang@company.com",
"category": "work",
"_type": "Email"
},
{
"_id": {...},
"active": false,
"value": "lanceh11@mymail.com",
"category": "personal",
"_type": "Email"
},
{
"_id": {...},
"active": true,
"_type": "Info"
},
{
"_id": {...},
"active": true,
"value": 1239007777,
"country": "USA",
"_type": "Phone"
}
]
}

Puedes cambiar el contexto de persistencia de una clase secundaria desde el contexto de persistencia de su clase principal para almacenar el documento en una ubicación diferente a la predeterminada. Mediante el método store_in, puedes almacenar una instancia de una clase secundaria en una colección, base de datos o clúster diferente al de una instancia del modelo principal.

Las siguientes definiciones de modelo demuestran cómo utilizar el método store_in para almacenar instancias de Employee y Manager en una colección diferente a la colección people:

class Person
include Mongoid::Document
end
class Employee < Person
# Specifies "employees" as target collection
store_in collection: :employees
end
class Manager < Employee
# Specifies "managers" as target collection
store_in collection: :managers
end

Nota

Mongoid aún añade el campo discriminador a los documentos almacenados.

Si configuras una colección objetivo alternativa en algunas clases hijas y no en otras, las instancias de las clases sin colecciones especificadas se almacenan en la colección asociada con la clase madre.

Nota

Cuando cambie la colección de destino para una clase secundaria, las instancias de esa clase no aparecerán en los resultados de las consultas sobre la clase principal.

Para obtener más información sobre cómo configurar la colección de destino para sus operaciones, consulte la Guíade configuración de persistencia.

Volver

Indexes

En esta página