Docs Menu
Docs Home
/ /

Realizar operaciones de datos

En esta guía, puede aprender a usar Mongoid para realizar operaciones CRUD (crear, leer, actualizar, eliminar) para modificar los datos en sus colecciones de MongoDB.

Mongoid admite operaciones CRUD que se pueden realizar con otros mapeadores de Ruby, como Active Record o Data Mapper. Al usar Mongoid, las operaciones de persistencia general realizan actualizaciones atómicas solo en los campos modificados, en lugar de escribir el documento completo en la base de datos cada vez, como ocurre con otros ODM.

Puede 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 puede usar para crear nuevos documentos.

Uso el create! Método en la clase del modelo para insertar uno o más documentos en una colección. Si se produce algún error de servidor o de validación, create! genera una excepción.

Para llamar a create!, pase un hash de atributos que definan el documento que desea insertar. Si desea crear e insertar varios documentos, pase una matriz de hashes.

Este ejemplo muestra varias maneras de llamar a create!. El primer ejemplo crea un documento Person y el segundo crea dos documentos Person. 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

Utilice el método create para insertar un nuevo documento o varios documentos nuevos en una base de datos. create no genera una excepción en caso de errores de validación, a diferencia de la versión con el sufijo !. create sí genera excepciones en caso de errores del servidor, como si 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 intenta insertar dos documentos Post, pero el segundo no pasa la validación porque contiene un título duplicado. El ejemplo utiliza 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.

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!

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.

Puede pasar las siguientes opciones a save:

  • validate: false:Para omitir las validaciones al guardar el nuevo documento o los atributos actualizados.

  • touch: false: Para no actualizar el campo updated_at al actualizar los atributos especificados. Esta opción no tiene efecto al insertar un nuevo documento.

El siguiente código usa save para insertar un nuevo documento. Luego, lo actualiza 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)

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 Especifique una guía de consulta de documentos.

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 utilizar attributes:

person = Person.new(first_name: "James", last_name: "Nan")
person.save
puts person.attributes
{ "_id" => BSON::ObjectId('...'),
"first_name" => "James",
"last_name" => "Nan"
}

Puede usar el método reload para acceder a la versión más reciente de un documento desde MongoDB. Al recargar un documento, Mongoid también recarga las asociaciones incrustadas en la misma consulta. Sin embargo, Mongoid no recarga las asociaciones referenciadas. En su lugar, borra estos valores para que se carguen desde la base de datos en 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 del documento band, pero no guarda el nuevo valor. Dado que Mongoid no conservó 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 encuentra un documento en la base de datos, genera un error Mongoid::Errors::DocumentNotFound por defecto. Puede configurar la opción raise_not_found_error como false en su archivo mongoid.yml para que Mongoid guarde un nuevo documento y restablezca sus atributos a los valores predeterminados. Generalmente, también cambia el valor del campo _id. Por este motivo, no recomendamos usar reload cuando raise_not_found_error esté configurado como false.

Cuando se llama a reload en un documento que no está persistente, el método realiza una consulta 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 operación find utilizando el valor _id del documento, lo que hace 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

Puede realizar operaciones de actualización para modificar documentos existentes en una colección. Si intenta actualizar un documento eliminado, Mongoid genera una excepción FrozenError.

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 de atributos anidados.

El método update_attributes no genera una excepción en caso de errores de validación. Devuelve true si supera la validación y el documento se actualiza, y false en caso contrario.

El siguiente ejemplo muestra cómo utilizar update_attributes:

person.update_attributes(
first_name: "Hasan",
last_name: "Emine"
)

Puede utilizar el update_attribute método para omitir las validaciones y actualizar un solo atributo de una instancia de 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")

Puede utilizar el método upsert para actualizar, insertar o reemplazar un documento.

upsert Acepta la opción replace. Si se establece esta opción en true y el documento que llama a upsert ya existe en la base de datos, el nuevo documento reemplaza al existente. Se eliminan los campos de la base de datos que el nuevo documento no reemplaza.

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)

Puede usar el método touch para actualizar la marca de tiempo updated_at de un documento a la hora actual. touch aplica la actualización en cascada a cualquiera de las asociaciones belongs_to del documento. También puede pasar otro campo con valor de tiempo como opción para actualizarlo también.

El siguiente ejemplo utiliza touch para actualizar las marcas de tiempo updated_at y audited_at:

person.touch(:audited_at)

Puede realizar operaciones de eliminación para quitar documentos de una colección.

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 utilizar el método delete y demuestra lo que sucede 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 genera un error Mongoid::Errors::DocumentNotFound cuando se llama a reload porque unsaved_person.delete elimina el documento person porque los dos documentos tienen el mismo valor para _id.

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 utilizar destroy:

person.destroy

El método delete_all elimina todos los documentos de la colección que están modelados por su clase de modelo Mongoid. delete_all no ejecuta devoluciones de llamadas.

El siguiente ejemplo muestra cómo usar delete_all para eliminar todos los Person documentos:

Person.delete_all

El método destroy_all elimina todos los documentos de la colección modelados por la clase de modelo de Mongoid. Esta operación puede ser costosa, ya que 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

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.

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 utilizar new_record?:

person = Person.new(
first_name: "Tunde",
last_name: "Adebayo"
)
puts person.new_record?
person.save!
puts person.new_record?
true
false

El atributo persisted? devuelve true si Mongoid persiste la instancia del modelo y false en caso contrario. Comprueba la condición opuesta a la del atributo new_record?.

El siguiente ejemplo muestra cómo utilizar persisted?:

person = Person.new(
first_name: "Kiana",
last_name: "Kahananui"
)
puts person.persisted?
person.save!
puts person.persisted?
false
true

Mongoid ofrece varias maneras de acceder a los valores de campo de un documento. Las siguientes secciones describen cómo acceder a ellos.

Hay varias maneras de obtener y establecer valores de campo en un documento. Si declara explícitamente un campo, puede obtener y establecer su valor directamente en el documento. El siguiente ejemplo muestra cómo establecer y obtener el campo first_name para una instancia Person:

class Person
include Mongoid::Document
field :first_name
end
person = Person.new
person.first_name = "Artem"
person.first_name # => "Artem"

El ejemplo anterior primero utiliza el atributo first_name para establecer un valor y luego lo llama nuevamente para recuperar el valor.

También puede usar los métodos [] y [] = en una instancia del modelo Mongoid para acceder a los atributos mediante la sintaxis hash. El método [] es un alias del método read_attribute y el método [] = es un alias del método write_attribute. El siguiente ejemplo muestra cómo obtener y configurar el campo con 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, consulte la siguiente sección read_attribute y write_attribute de esta guía.

Puede usar los métodos read_attribute y write_attribute para especificar un comportamiento personalizado al leer o escribir campos. Puede usar estos métodos al definir un modelo o invocándolos en instancias del 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 escribir 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">

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 usar el método write_attributes, invoque el método en una instancia del modelo y pase los campos y valores que desee configurar. 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",
)

Mongoid ofrece compatibilidad con los siguientes operadores de actualización, que se pueden llamar como métodos en las instancias del modelo. Estos métodos realizan operaciones de forma automática y omiten validaciones y devoluciones de llamadas.

La siguiente tabla describe los operadores compatibles con Mongoid:

Operador
Descripción
Ejemplo

add_to_set

Agrega un valor especificado a un campo con valor de matriz.

person.add_to_set(aliases: "Bond")

bit

Realiza una actualización bit a bit de un campo.

person.bit(age: { and: 10, or: 12 })

inc

Incrementa el valor de un campo.

person.inc(age: 1)

pop

Elimina el primer o el último elemento de un campo de matriz.

person.pop(aliases: 1)

pull

Elimina todas las instancias de un valor o valores que coinciden con una condición especificada de un campo de matriz.

person.pull(aliases: "Bond")

pull_all

Elimina todas las instancias de los valores especificados de un campo de matriz.

person.pull_all(aliases: [ "Bond", "James" ])

push

Añade un valor especificado a un campo de matriz.

person.push(aliases: ["007","008"])

rename

Cambia el nombre de un campo en todos los documentos coincidentes.

person.rename(bday: :dob)

set

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.
person = Person.create!(name: "Ricky Bobby")
# Updates `name` in the database
person.set(name: "Tyler Durden")

unset

Elimina un campo particular en todos los documentos coincidentes.

person.unset(:name)

Para obtener más información sobre los operadores de actualización, consulte Operadores de actualización en el manual de MongoDB Server.

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 utilizar atomically para actualizar de forma atómica varios 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. De forma predeterminada, Mongoid realiza escrituras atómicas definidas por cada bloque al finalizar este. El siguiente ejemplo muestra cómo anidar bloques atomically:

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.

El método atomically acepta la opción join_context: true para especificar que las operaciones se ejecuten 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, escribe cambios en la base de datos. El siguiente ejemplo establece 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 establece globalmente join_contexts en true, puede usar la opción join_context: false en un bloque atomically para ejecutar operaciones al final del bloque solo para ese bloque.

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.

Mongoid registra los cambios desde que se instancia un modelo, ya sea como un nuevo documento o al recuperar uno 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 permiten explorar los cambios en una instancia del mismo. El siguiente código muestra cómo ver los cambios en la instancia del 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

Establecer las asociaciones en un documento no modifica los hashes changes ni changed_attributes. Esto aplica a todos los tipos de asociaciones. Sin embargo, al cambiar el campo _id en las asociaciones referenciadas, los cambios se reflejan en los hashes changes y changed_attributes.

Puede 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"

Mongoid utiliza el seguimiento de errores como base de todas sus operaciones de persistencia. Evalúa los cambios en un documento y actualiza automáticamente solo lo que ha cambiado, a diferencia de otros frameworks que escriben el documento completo cada vez que se guarda. Si no se realizan cambios, Mongoid no accede a la base de datos al llamar a Model#save.

Tras persistir un modelo en MongoDB, Mongoid borra los cambios actuales. Sin embargo, aún puede ver los cambios realizados 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" ] }

Mongoid presenta actualmente un problema que impide que los cambios en los atributos de los tipos de contenedor, como Set o Array, se guarden en MongoDB. Debe asignar todos los campos, incluidos los tipos de contenedor, para que sus valores se guarden en MongoDB.

Por ejemplo, agregar un elemento a una Set instancia como se muestra en el siguiente código no conserva los cambios en MongoDB:

person = Person.new
person.interests
# => #<Set: {}>
person.interests << 'Hiking'
# => #<Set: {"Hiking"}>
person.interests
# => #<Set: {}> # Change does not take effect

Para conservar este cambio, debe modificar el valor del campo fuera del modelo y volver a asignarlo 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"}>

Puede marcar documentos como de solo lectura de las siguientes maneras, según el valor del indicador de función Mongoid.legacy_readonly:

  • Si esta opción está desactivada, puede marcar un documento como de solo lectura llamando al readonly! método en ese documento. El documento de solo lectura resultante genera un ReadonlyDocument error si intenta realizar cualquier operación de persistencia, como guardar, actualizar, eliminar y destruir. Tenga en cuenta 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 como only o without. De esta forma, no es posible borrar ni destruir el documento de solo lectura porque Mongoid genera un error ReadonlyDocument, 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

Para obtener más información sobre cómo especificar filtros de consulta, consulte la guía Especificar una consulta de documento.

Para obtener más información sobre cómo configurar reglas de validación en sus modelos, consulte la guía Validación de documentos.

Para obtener más información sobre cómo definir devoluciones de llamadas, consulte la guía Personalizar devoluciones de llamadas para modelos de datos.

Volver

Interacción con los datos