Overview
En esta guía, podrás aprender cómo utilizar Mongoid para realizar operaciones CRUD (crear, leer, actualizar, borrar) para modificar los datos en tus colecciones de MongoDB.
Mongoid admite operaciones CRUD que puedes realizar utilizando otros mapeadores de Ruby, como Active Record o Data Mapper. Cuando usas Mongoid, las operaciones generales de persistencia realizan actualizaciones atómicas solo en los campos que cambias en lugar de escribir todo el documento en la base de datos cada vez, como ocurre con otros ODM.
Crear operaciones
Puedes realizar operaciones de creación para añadir nuevos documentos a una colección. Si la colección no existe, la operación la crea implícitamente. Las siguientes secciones describen los métodos que puedes utilizar para crear nuevos documentos.
¡crea!
Usa el create! método en tu clase de modelo para insertar uno o más documentos en una colección. Si ocurre algún error de servidor o de validación, create! genera una excepción.
Para llamar a create!, pasa un hash de atributos que definan el documento que deseas insertar. Si deseas crear e insertar múltiples documentos, pasa un arreglo de hashes.
Este ejemplo muestra múltiples formas de llamar a create!. El primer ejemplo crea un único Person documento, y el segundo ejemplo crea dos Person documentos. El tercer ejemplo pasa un bloque do..end a create!. Mongoid invoca este bloque con los documentos pasados a create! como argumentos. El método create! intenta guardar el documento al final del bloque:
Person.create!( first_name: "Heinrich", last_name: "Heine" ) Person.create!([ { first_name: "Heinrich", last_name: "Heine" }, { first_name: "Willy", last_name: "Brandt" } ]) Person.create!(first_name: "Heinrich") do |doc| doc.last_name = "Heine" end
Cree
Utiliza el método create para insertar un nuevo documento o varios nuevos documentos en una base de datos. create no lanza una excepción en errores de validación, a diferencia de la versión con sufijo !. create sí arroja excepciones en errores de servidor, como cuando se inserta un documento con un campo _id duplicado.
Si create encuentra algún error de validación, el documento no se inserta, sino que se devuelve junto con otros documentos insertados. Puede usar los métodos persisted?, new_record? o errors para verificar los documentos insertados en la base de datos.
Este ejemplo muestra cómo usar create para insertar nuevos documentos en MongoDB. El primer ejemplo muestra cómo insertar un documento Person. El segundo ejemplo intenta insertar dos Post documentos, pero el segundo documento no pasa la validación porque contiene un título duplicado. El ejemplo utiliza entonces el método persisted? para confirmar qué documentos se insertaron correctamente en la colección:
Person.create( first_name: "Heinrich", last_name: "Heine" ) class Post include Mongoid::Document validates_uniqueness_of :title end posts = Post.create([{title: "test"}, {title: "test"}]) posts.map { |post| post.persisted? } # => [true, false]
Para obtener más información sobre los métodos persisted? y new_record?, consulte la SecciónAtributos de persistencia de esta guía.
save!
Utiliza el método save! para guardar atómicamente los atributos modificados en la colección o para insertar un nuevo documento. save! genera una excepción si hay algún error de servidor o de validación. Puedes utilizar el método new para crear una nueva instancia de documento. Luego, utiliza save! para insertar el documento en la base de datos.
El siguiente ejemplo muestra cómo utilizar save! para insertar un nuevo documento Person y actualizar el campo first_name del documento existente:
person = Person.new( first_name: "Esmeralda", last_name: "Qemal" ) person.save! person.first_name = "Malik" person.save!
guardar
El método save no genera una excepción si hay errores de validación. save sigue arrojando una excepción si hay errores del servidor. El método devuelve true si todos los atributos modificados se guardan, y false si se producen errores de validación.
Puedes pasar las siguientes opciones a save:
validate: falsePara omitir las validaciones al guardar el nuevo documento o los atributos actualizados.touch: false: Para que no se actualice el campoupdated_atal actualizar los atributos especificados. Esta opción no tiene efecto al insertar un nuevo documento.
El siguiente código utiliza save para insertar un nuevo documento. Luego, actualiza ese documento y aplica la opción validate: false.
person = Person.new( first_name: "Tamara", last_name: "Graham" ) person.save person.first_name = "Aubrey" person.save(validate: false)
Operaciones de lectura
Puede realizar operaciones de lectura para recuperar documentos de una colección. Para obtener más información sobre cómo crear filtros de consulta para recuperar un subconjunto de sus documentos, consulte Especifica una query de documento guía.
atributos
Se puede usar el método attributes para recuperar los atributos de una instancia de modelo como un hash. Este hash también contiene los atributos de todos los documentos incrustados.
El siguiente ejemplo muestra cómo usar attributes:
person = Person.new(first_name: "James", last_name: "Nan") person.save puts person.attributes
{ "_id" => BSON::ObjectId('...'), "first_name" => "James", "last_name" => "Nan" }
recargar
Puedes usar el método reload para acceder a la versión más reciente de un documento desde MongoDB. Cuando recargas un documento, Mongoid también recarga todas las asociaciones integradas en la misma query. Sin embargo, Mongoid no vuelve a cargar las asociaciones referenciadas. En su lugar, borra estos valores para que se carguen desde la base de datos durante el siguiente acceso.
Al llamar a reload en un documento, se pierden los cambios no guardados. El siguiente código muestra cómo llamar a reload en un documento:
band = Band.create!(name: 'Sun 1') # => #<Band _id: ..., name: "Sun 1"> band.name = 'Moon 2' # => #<Band _id: ..., name: "Moon 2"> band.reload # => #<Band _id: ..., name: "Sun 1">
El ejemplo anterior actualiza el campo name en el documento band, pero no guarda el valor nuevo. Como Mongoid no persistió el cambio en el valor name, name contiene el valor original guardado en la base de datos.
Nota
Errores de documento no encontrado
Cuando Mongoid no puede encontrar un documento en la base de datos, por defecto genera un error Mongoid::Errors::DocumentNotFound. Se puede establecer la opción configuración raise_not_found_error en false en su archivo mongoid.yml para indicar a Mongoid que guarde un nuevo documento y establezca sus atributos a valores por defecto. En general, también cambia el valor del campo _id. Por este motivo, no recomendamos utilizar reload cuando raise_not_found_error está configurado en false.
Recargar documentos no guardados
Cuando llamas a reload en un documento que no se ha persistido, el método realiza una query find sobre el valor _id del documento.
El siguiente ejemplo llama a reload en un documento que no se ha guardado e imprime el valor del campo name. reload realiza una find operación utilizando el valor _id del documento, lo que genera que Mongoid recupere el documento existente en la colección:
existing = Band.create!(name: 'Photek') band = Band.new(id: existing.id) band.reload puts band.name
Photek
Operaciones de actualizar
Puedes realizar operaciones de actualización para modificar los documentos existentes de una colección. Si intentas actualizar un documento eliminado, Mongoid genera una excepción FrozenError.
update_attributes!
Se puede utilizar el método update_attributes! para actualizar los atributos de una instancia de modelo existente. Este método genera una excepción si encuentra algún error de validación o del servidor.
El siguiente ejemplo muestra cómo utilizar update_attributes! para actualizar los atributos first_name y last_name de un documento existente:
person.update_attributes!( first_name: "Maximilian", last_name: "Hjalmar" )
Tip
Mongoid ofrece la función de atributos anidados, que permite actualizar un documento y sus asociaciones anidadas en una sola llamada. Para obtener más información, consulte la guía «Usar atributos anidados».
update_attributes
El método update_attributes no genera una excepción en caso de errores de validación. El método devuelve true si pasa la validación y el documento se actualiza, y false en caso contrario.
El siguiente ejemplo muestra cómo usar update_attributes:
person.update_attributes( first_name: "Hasan", last_name: "Emine" )
update_attribute
Puede usar el método update_attribute para omitir las validaciones y actualizar un atributo único de una instancia modelo.
El siguiente ejemplo muestra cómo usar update_attribute para actualizar el valor del atributo first_name de un documento:
person.update_attribute(:first_name, "Jean")
inserción
Puedes usar el método upsert para actualizar, insertar o reemplazar un documento.
upsert acepta una opción replace. Si configuras esta opción en true y el documento que invoca upsert ya existe en la base de datos, el nuevo documento reemplazará al que está en la base de datos. Se eliminan todos los campos en la base de datos que el nuevo documento no reemplace.
Si configura la opción replace en false y el documento existe en la base de datos, se actualiza. Mongoid no modifica ningún campo aparte de los especificados en el documento de actualización. Si el documento no existe en la base de datos, se inserta con los campos y valores especificados en el documento de actualización. La opción replace está configurada en false por defecto.
El siguiente ejemplo muestra cómo usar upsert para insertar primero un nuevo documento y luego reemplazarlo estableciendo replace: true:
person = Person.new( first_name: "Balu", last_name: "Rama" ) person.upsert person.first_name = "Ananda" person.upsert(replace: true)
contacto
Puede usar el método touch para actualizar la marca de tiempo updated_at de un documento a la hora actual. touch propaga la actualización a cualquiera de las asociaciones belongs_to del documento. También puede pasar otro campo con valor de tiempo como una opción para actualizar también ese campo.
El siguiente ejemplo utiliza touch para actualizar las marcas de tiempo updated_at y audited_at:
person.touch(:audited_at)
Operaciones de borrar
Puedes realizar operaciones de borrado para remover documentos de una colección.
borrar
Puede usar el método delete para eliminar un documento de la base de datos. Al usar delete, Mongoid no ejecuta ninguna devolución de llamada. Si el documento no se guarda en la base de datos, delete intenta eliminar cualquier documento con el mismo valor _id.
El siguiente ejemplo muestra cómo usar el método delete y demuestra qué ocurre cuando se elimina un documento que no está guardado en la base de datos:
person = Person.create!(name: 'Edna Park') unsaved_person = Person.new(id: person.id) unsaved_person.delete person.reload
En el ejemplo anterior, Mongoid produce un error Mongoid::Errors::DocumentNotFound cuando llamas a reload porque unsaved_person.delete elimina el documento person debido a que ambos documentos tienen el mismo valor para _id.
destruir
El método destroy funciona de forma similar a delete, excepto que Mongoid ejecuta devoluciones de llamada al llamar a destroy. Si el documento no se encuentra en la base de datos, destroy intenta eliminar cualquier documento con el mismo _id.
El siguiente ejemplo muestra cómo usar destroy:
person.destroy
delete_all
El método delete_all elimina todos los documentos de la colección que estén modelados por tu clase modelo de Mongoid. delete_all no ejecuta callbacks.
El siguiente ejemplo muestra cómo usar delete_all para eliminar todos los Person documentos:
Person.delete_all
destruir_todo
El método destroy_all elimina todos los documentos de la colección que estén modelados por tu clase modelo de Mongoid. Esta puede ser una operación costosa porque Mongoid carga todos los documentos en memoria.
El siguiente ejemplo muestra cómo usar destroy_all para eliminar todos los Person documentos:
Person.destroy_all
Atributos de persistencia
Las siguientes secciones describen los atributos que Mongoid proporciona y que puedes usar para verificar si un documento se incorpora a la base de datos.
nuevo_registro?
El new_record? atributo devuelve true si la instancia del modelo aún no se ha guardado en la base de datos y en false caso contrario. Comprueba la condición opuesta persisted? a la del atributo.
El siguiente ejemplo muestra cómo usar new_record?:
person = Person.new( first_name: "Tunde", last_name: "Adebayo" ) puts person.new_record? person.save! puts person.new_record?
true false
¿persistió?
El atributo persisted? devuelve true si Mongoid persiste la instancia del modelo y false en caso contrario. Verifica lo contrario que el atributo new_record?.
El siguiente ejemplo muestra cómo usar persisted?:
person = Person.new( first_name: "Kiana", last_name: "Kahananui" ) puts person.persisted? person.save! puts person.persisted?
false true
Acceso a los valores de campo
Mongoid ofrece varias maneras de acceder a los valores de campo de un documento. Las siguientes secciones describen cómo acceder a ellos.
Obtener y establecer valores de campo
Hay múltiples formas de obtener y establecer valores de campo en un documento. Si declaras explícitamente un campo, puedes obtener y establecer este valor de campo en el documento directamente. El siguiente ejemplo muestra cómo establecer y obtener el campo first_name de una instancia Person:
class Person include Mongoid::Document field :first_name end person = Person.new person.first_name = "Artem" person.first_name # => "Artem"
En el ejemplo anterior, primero se utiliza el atributo first_name para establecer un valor y luego se vuelve a llamar para recuperar el valor.
También puedes usar los métodos [] y [] = en una instancia del modelo Mongoid para acceder a los atributos usando la sintaxis hash. El método [] es un alias para el método read_attribute y el método [] = es un alias para el método write_attribute. El siguiente ejemplo muestra cómo obtener y establecer el campo alias first_name mediante los métodos [] y []=:
class Person include Mongoid::Document field :first_name, as: :fn end person = Person.new(first_name: "Artem") person["fn"] # => "Artem" person[:first_name] = "Vanya" # => "Artem" person # => #<Person _id: ..., first_name(fn): "Vanya">
Para obtener más información sobre estos métodos, consulta la siguientes sección de read_attribute y write_attribute de esta guía.
atributo_de_lectura y atributo_de_escritura
Puede utilizar los métodos read_attribute y write_attribute para especificar un comportamiento personalizado al leer o escribir campos. Puedes utilizar estos métodos al definir un modelo o llamándolos en instancias de modelo.
Para usar read_attribute para obtener un campo, pase su nombre al método. Para usar write_attribute para definir un campo, pase su nombre y el valor que se asignará.
El siguiente ejemplo utiliza read_attribute y write_attribute en una definición de modelo para definir first_name y first_name= como métodos que se utilizan para leer y guardar en el atributo fn:
class Person include Mongoid::Document def first_name read_attribute(:fn) end def first_name=(value) write_attribute(:fn, value) end end person = Person.new person.first_name = "Artem" person.first_name # => "Artem"
También puede llamar a read_attribute y write_attribute directamente en una instancia de modelo para obtener y establecer atributos. El siguiente ejemplo utiliza estos métodos en una instancia de modelo para obtener el atributo first_name y establecerlo en el valor "Pushkin".
class Person include Mongoid::Document field :first_name, as: :fn end person = Person.new(first_name: "Artem") # => #<Person _id: ..., first_name(fn): "Artem"> person.read_attribute(:first_name) # => "Artem" person.read_attribute(:fn) # => "Artem" person.write_attribute(:first_name, "Pushkin") person # => #<Person _id: ..., first_name(fn): "Pushkin">
Guardado masivo de atributos
Puede escribir en varios campos al mismo tiempo utilizando los métodos attributes= o write_attributes en una instancia de modelo.
Para usar el método attributes=, invoque el método en una instancia del modelo y pase un objeto hash que contenga los campos y valores que desea configurar. El siguiente ejemplo muestra cómo usar el método attributes= para configurar los campos first_name y middle_name en un documento person:
person.attributes = { first_name: "Jean-Baptiste", middle_name: "Emmanuel" }
Para utilizar el método write_attributes, llama al método en una instancia de modelo e introduce los campos y valores que deseas fijar. El siguiente ejemplo muestra cómo usar el método write_attributes para configurar los campos first_name y middle_name en un documento person:
person.write_attributes( first_name: "Jean-Baptiste", middle_name: "Emmanuel", )
Operadores de actualización atómica
Mongoid ofrece soporte para los siguientes operadores de actualización que puedes llamar como métodos en instancias de modelos. Estos métodos realizan operaciones de forma atómica y omiten validaciones y funciones de retorno.
La siguiente tabla describe los operadores compatibles con Mongoid:
Operador | Descripción | Ejemplo | |||
|---|---|---|---|---|---|
| Añade un valor especificado a un campo cuyo valor es un arreglo. |
| |||
| Realiza una actualización bit a bit de un campo. |
| |||
| Incrementa el valor de un campo. |
| |||
| Elimina el primer o el último elemento de un campo de matriz. |
| |||
| Elimina todas las instancias de un valor o valores que coinciden con una condición especificada de un campo de matriz. |
| |||
| Elimina todas las instancias de los valores especificados de un campo de arreglo. |
| |||
| Agrega un valor especificado a un campo de arreglo. |
| |||
| Cambia el nombre de un campo en todos los documentos coincidentes. |
| |||
| Updates an attribute on the model instance and, if the instance
is already persisted, performs an atomic $set on the field, bypassing
validations.set can also deeply set values on Hash fields.set can also deeply set values on embeds_one associations.
If a model instance's embeds_one association document is nil, one
is created before the update.set cannot be used with has_one associations. | | |||
| Elimina un campo en particular de todos los documentos coincidentes. |
|
Para obtener más información sobre los operadores de actualización, consulte Operadores de actualización en el manual de MongoDB Server.
Operaciones atómicas grupales
Para agrupar operaciones atómicas, puede usar el método atomically en una instancia de modelo. Mongoid envía todas las operaciones que pasa a un bloque atomically en un solo comando atómico.
Nota
Utilice transacciones para modificar múltiples documentos de forma atómica
Las operaciones atómicas se aplican a un solo documento a la vez. Por lo tanto, los atomically bloques anidados no pueden realizar cambios en varios documentos en una sola operación atómica. Para realizar cambios en varios documentos en una sola operación atómica, utilice una transacción multidocumento. Para obtener más información sobre las transacciones, consulte la guía Transacciones y sesiones.
El siguiente ejemplo muestra cómo usar atomically para actualizar de forma atómica múltiples campos en un documento:
person.atomically do person.inc(age: 1) person.set(name: 'Jake') end
Puedes anidar bloques #atomically al actualizar un solo documento. Por defecto, Mongoid realiza escrituras atómicas definidas por cada bloque cuando el bloque finaliza. El siguiente ejemplo muestra cómo anidar atomically bloques:
person.atomically do person.atomically do person.inc(age: 1) person.set(name: 'Jake') end raise 'An exception' # Name and age changes are persisted end
En el ejemplo anterior, las operaciones $inc y $set se ejecutan al final del bloque interno atomically.
Unirse a Contexts
El método atomically acepta una opción join_context: true para especificar que las operaciones se ejecutarán al final del bloque atomically más externo. Al habilitar esta opción, solo el bloque más externo, o el primer bloque donde join_context es false, guardará los cambios en la base de datos. El siguiente ejemplo configura la opción join_context en true:
person.atomically do person.atomically(join_context: true) do person.inc(age: 1) person.set(name: 'Jake') end raise 'An exception' # Name and age changes are not persisted end
En el ejemplo anterior, Mongoid realiza las operaciones $inc y $set al final del bloque atomically más externo. Sin embargo, dado que se genera una excepción antes de que finalice el bloque y estas operaciones puedan ejecutarse, los cambios no se conservan.
También puedes habilitar la unión de contexto a nivel global, para que las operaciones se ejecuten en el bloque atomically más externo por defecto. Para habilitar esta opción a nivel global, define la opción de configuración join_contexts en true en tu archivo mongoid.yml. Para aprender más sobre las opciones de configuración de Mongoid, consulta Opciones de archivo de configuración autogestionadas.
Cuando se configura globalmente join_contexts a true, se puede utilizar la opción join_context: false en un bloque atomically para ejecutar operaciones al final de ese bloque solo para ese bloque.
Seguimiento sucio
Puedes rastrear los campos cambiados ("modificados") utilizando una API de Mongoid similar a la disponible en Active Model. Si modificas un campo definido en un modelo, Mongoid marca el modelo como modificado y te permite realizar acciones especiales. Las siguientes secciones describen cómo puedes interactuar con modelos modificados.
Ver cambios
Mongoid registra los cambios desde el momento en que se instancia un modelo, ya sea como un nuevo documento o al recuperarlo de la base de datos, hasta que se guarda. Cualquier operación de persistencia borra los cambios.
Mongoid crea métodos específicos del modelo que te permiten explorar los cambios en una instancia del modelo. El siguiente código muestra maneras de ver los cambios en la instancia de tu modelo:
# Retrieves a person instance person = Person.first # Sets a new `name` value person.name = "Sarah Frank" # Checks to see if the document is changed person.changed? # true # Gets an array of changed fields. person.changed # [ :name ] # Gets a hash of the old and changed values for each field person.changes # { "name" => [ "Sarah Frink", "Sarah Frank" ] } # Checks if a specific field is changed person.name_changed? # true # Gets the changes for a specific field person.name_change # [ "Sarah Frink", "Sarah Frank" ] # Gets the previous value for a field person.name_was # "Sarah Frink"
Nota
Seguimiento de cambios en las asociaciones
Configurar las asociaciones en un documento no modifica los hashes changes o changed_attributes. Esto es válido para todos los tipos de asociaciones. Sin embargo, cambiar el campo _id en las asociaciones referenciadas hace que los cambios se muestren en los hashes changes y changed_attributes.
Restablecer cambios
Puedes restablecer un campo modificado a su valor anterior llamando al método reset, como se muestra en el siguiente código:
person = Person.first person.name = "Sarah Frank" # Reset the changed `name` field person.reset_name! person.name # "Sarah Frink"
Persistencia
Mongoid utiliza el seguimiento de cambios como base de todas las operaciones de persistencia. Evalúa los cambios en un documento y actualiza de forma atómica solo lo que ha cambiado, en comparación con otros marcos que sobreescriben todo el documento en cada guardado. Si no realiza ningún cambio, Mongoid no accede a la base de datos cuando llama a Model#save.
Ver cambios anteriores
Después de persistir un modelo en MongoDB, Mongoid borra los cambios actuales. Sin embargo, todavía se puede ver qué cambios se hicieron previamente llamando al método previous_changes, como se muestra en el siguiente código:
person = Person.first person.name = "Sarah Frank" person.save # Clears out current changes # Lists the previous changes person.previous_changes # { "name" => [ "Sarah Frink", "Sarah Frank" ] }
Actualizar campos del contenedor
Mongoid tiene actualmente un problema que impide guardar en MongoDB los cambios en los atributos de tipos de contenedores, como Set o Array. Debe asignar todos los campos, incluidos los tipos de contenedores, para que sus valores se guarden en MongoDB.
Por ejemplo, agregar un elemento a una instancia Set como se muestra en el siguiente código no guarda los cambios en MongoDB:
person = Person.new person.interests # => #<Set: {}> person.interests << 'Hiking' # => #<Set: {"Hiking"}> person.interests # => #<Set: {}> # Change does not take effect
Para mantener este cambio, es necesario modificar el valor del campo fuera del modelo y asignarlo de nuevo al modelo, como se muestra en el siguiente código:
person = Person.new interests = person.interests # => #<Set: {}> interests << 'Hiking' # => #<Set: {"Hiking"}> # Assigns the Set to the field person.interests = interests # => #<Set: {"Hiking"}> person.interests # => #<Set: {"Hiking"}>
Documentos de solo lectura
Puede marcar documentos como de solo lectura de las siguientes maneras, según el valor del indicador de función Mongoid.legacy_readonly:
Si se desactiva este indicador, puedes marcar un documento como de solo lectura llamando al
readonly!método en ese documento. El documento resultante, de solo lectura, genera un error deReadonlyDocumentsi se intenta realizar cualquier operación de persistencia, incluyendo, pero no limitado a, guardar, actualizar, borrar y destruir. Note que recargar no restablece el estado de solo lectura.person = Person.first person.readonly? # => false person.readonly! # Sets the document as read-only person.readonly? # => true person.name = "Larissa Shay" # Changes the document person.save # => raises ReadonlyDocument error person.reload.readonly? # => true Si esta indicador está activada
on, puedes marcar un documento como de solo lectura después de aplicarle la proyección usando métodos comoonlyowithout. De esta forma, no es posible borrar ni destruir el documento de solo lectura porque Mongoid genera un errorReadonlyDocument, aunque sí es posible guardarlo y actualizarlo. El estado de solo lectura se restablece si se vuelve a cargar el documento.person = Person.only(:name).first person.readonly? # => true person.destroy # => raises ReadonlyDocument error person.reload.readonly? # => false Tip
Proyección
Para obtener más información sobre las proyecciones, consulte la sección Devolver campos especificados de la guía Modificar resultados de consulta.
También puedes hacer que un documento sea de solo lectura sobrescribiendo el método readonly?, como se muestra en el siguiente código:
class Person include Mongoid::Document field :name, type: String def readonly? true end end person = Person.first person.readonly? # => true person.destroy # => raises ReadonlyDocument error
Información Adicional
Para obtener más información sobre cómo especificar los filtros de query, revisa la guía Especificar una query de documento.
Para obtener más información sobre cómo configurar reglas de validación en sus modelos, consulte la guía Configurar validación de documentos.
Para obtener más información sobre cómo definir funciones de devolución de llamada, consulte la guía Personalizar funciones de devolución de llamada para modelos.