Perform Data Operations
On this page
- Overview
- Create Operations
- create!
- create
- save!
- save
- Read Operations
- attributes
- reload
- Update Operations
- update_attributes!
- update_attributes
- update_attribute
- upsert
- touch
- Delete Operations
- delete
- destroy
- delete_all
- destroy_all
- Persistence Attributes
- new_record?
- persisted?
- Access Field Values
- Get and Set Field Values
- read_attribute and write_attribute
- Bulk Write Attributes
- Atomic Update Operators
- Group Atomic Operations
- Dirty Tracking
- View Changes
- Reset Changes
- Persistence
- View Previous Changes
- Update Container Fields
- Read-only Documents
- Additional Information
Overview
In this guide, you can learn how to use Mongoid to perform CRUD (create, read, update, delete) operations to modify the data in your MongoDB collections.
Mongoid supports CRUD operations that you can perform by using other Ruby mappers such as Active Record or Data Mapper. When using Mongoid, general persistence operations perform atomic updates on only the fields that you change instead of writing the entire document to the database each time, as is the case with other ODMs.
Create Operations
You can perform create operations to add new documents to a collection. If the collection doesn't exist, the operation implicitly creates the collection. The following sections describe the methods you can use to create new documents.
create!
Use the create!
method on your model class to insert one or more
documents into a collection. If any server or validation errors occur,
create!
raises an exception.
To call create!
, pass a hash of attributes that define the document
you want to insert. If you want to create and insert multiple documents,
pass an array of hashes.
This example shows multiple ways to call create!
. The first example
creates one Person
document, and the second example creates two Person
documents. The third example passes a do..end
block to create!
. Mongoid
invokes this block with the documents passed to create!
as
arguments. The create!
method attempts to save the document at the
end of the block:
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
create
Use the create
method to insert a new document or multiple new documents into a
database. create
does not raise an exception on validation errors,
unlike the !
-suffixed version. create
does raise exceptions on
server errors, such as if you insert a document with a duplicate _id
field.
If create
encounters any validation errors, the document is not inserted
but is returned with other documents that were inserted. You can use the
persisted?
, new_record?
or errors
methods to verify the
documents that were inserted into the database.
This example shows how to use create
to insert new documents
into MongoDB. The first example shows how to insert a Person
document. The second example attempts to insert two Post
documents,
but the second document fails validation because it contains a duplicate
title. The example then uses the persisted?
method to confirm which
documents were successfully inserted into the collection:
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]
To learn more about the persisted?
and new_record?
methods, see
the Persistence Attributes section of this guide.
save!
Use the save!
method to atomically save changed attributes to the collection or
to insert a new document. save!
raises an exception if there are any
server or validation errors. You can use the new
method to create a new document
instance. Then, use save!
to insert the document into the database.
The following example shows how to use save!
to insert a new Person
document and update the first_name
field of the existing document:
person = Person.new( first_name: "Esmeralda", last_name: "Qemal" ) person.save! person.first_name = "Malik" person.save!
save
The save
method does not raise an exception if there are any
validation errors. save
still raises an exception if there are any
server errors. The method returns true
if all changed attributes
are saved, and false
if any validation errors occur.
You can pass the following options to save
:
validate: false
: To bypass validations when saving the new document or updated attributes.touch: false
: To not update theupdated_at
field when updating the specified attributes. This option has no effect when inserting a new document.
The following code uses save
to insert a new document. It then updates
that document and applies the validate: false
option.
person = Person.new( first_name: "Tamara", last_name: "Graham" ) person.save person.first_name = "Aubrey" person.save(validate: false)
Read Operations
You can perform read operations to retrieve documents from a collection. To learn more about creating query filters to retrieve a subset of your documents, see the Specify a Query guide.
attributes
You can use the attributes
method to retrieve the attributes of a
model instance as a hash. This hash also contains the attributes of all
embedded documents.
The following example shows how to use attributes
:
person = Person.new(first_name: "James", last_name: "Nan") person.save puts person.attributes
{ "_id" => BSON::ObjectId('...'), "first_name" => "James", "last_name" => "Nan" }
reload
You can use the reload
method to access the most recent version of a
document from MongoDB. When you reload a document, Mongoid also reloads any embedded
associations in the same query. However, Mongoid does not reload
referenced associations. Instead, it clears these values so that they
are loaded from the database during the next access.
When you call reload
on a document, any unsaved changes to the document
are lost. The following code shows how to call reload
on a document:
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">
The preceding example updates the name
field on the band
document,
but does not save the new value. Because Mongoid did not persist the
change to the name
value, name
contains the original value saved
to the database.
Note
Document Not Found Errors
When Mongoid cannot find a document in the database, by default it raises a
Mongoid::Errors::DocumentNotFound
error. You can set the
raise_not_found_error
configuration option to false
in your mongoid.yml
file to direct Mongoid to save a new document and set its attributes to
default values. Generally, it also changes the value of the _id
field. For this reason, we do not recommend using reload
when
raise_not_found_error
is set to false
.
Reload Unsaved Documents
When you call reload
on a document that is not persisted, the method performs
a find
query on the document's _id
value.
The following example calls reload
on a document that has not been
saved and prints out the name
field value. reload
performs a
find
operation using the document's _id
value, which causes
Mongoid to retrieve the existing document in the collection:
existing = Band.create!(name: 'Photek') band = Band.new(id: existing.id) band.reload puts band.name
Photek
Update Operations
You can perform update operations to modify existing documents in a
collection. If you attempt to update a deleted document, Mongoid raises
a FrozenError
exception.
update_attributes!
You can use the update_attributes!
method to update the attributes of an
existing model instance. This method raises an exception if it encounters
any validation or server errors.
The following example shows how to use update_attributes!
to update
the first_name
and last_name
attributes of an existing document:
person.update_attributes!( first_name: "Maximilian", last_name: "Hjalmar" )
Tip
Mongoid provides the nested attributes feature that allows you to update a document and its nested associations in one call. To learn more, see the Nested Attributes guide.
update_attributes
The update_attributes
method does not raise an exception on
validation errors. The method returns true
if it passes validation
and the document is updated, and false
otherwise.
The following example shows how to use update_attributes
:
person.update_attributes( first_name: "Hasan", last_name: "Emine" )
update_attribute
You can use the update_attribute
method to bypass validations and
update a single attribute of a model instance.
The following example shows how to use update_attribute
to update
the value of a document's first_name
attribute:
person.update_attribute(:first_name, "Jean")
upsert
You can use the upsert
method to update, insert, or replace a
document.
upsert
accepts a replace
option. If you set this option to true
and the document that calls upsert
already exists in the database,
the new document replaces the one in the database. Any fields in the
database that the new document does not replace are removed.
If you set the replace
option to false
and the document exists in the
database, it is updated. Mongoid does not change any fields other than the
ones specified in the update document. If the document does not exist in the
database, it is inserted with the fields and values specified in the
update document. The replace
option is set to false
by default.
The following example shows how to use upsert
to first insert a new
document, then replace it by setting replace: true
:
person = Person.new( first_name: "Balu", last_name: "Rama" ) person.upsert person.first_name = "Ananda" person.upsert(replace: true)
touch
You can use the touch
method to update a document's updated_at
timestamp to the current time. touch
cascades the update to any of
the document's belongs_to
associations. You can also pass another
time-valued field as an option to also update that field.
The following example uses touch
to update the
updated_at
and audited_at
timestamps:
person.touch(:audited_at)
Delete Operations
You can perform delete operations to remove documents from a collection.
delete
You can use the delete
method to delete a document from the database. When you
use delete
, Mongoid does not run any callbacks. If the document is not
saved to the database, delete
attempts to delete any document with
the same _id
value.
The following example shows how to use the delete
method and
demonstrates what happens when you delete a document that is not saved
to the database:
person = Person.create!(name: 'Edna Park') unsaved_person = Person.new(id: person.id) unsaved_person.delete person.reload
In the preceding example, Mongoid raises a Mongoid::Errors::DocumentNotFound
error when you call reload
because unsaved_person.delete
deletes
the person
document because the two documents have the same value
for _id
.
destroy
The destroy
method operates similarly to delete
, except Mongoid
runs callbacks when you call destroy
. If the document is not found
in the database, destroy
attempts to delete any document with
the same _id
.
The following example shows how to use destroy
:
person.destroy
delete_all
The delete_all
method deletes all documents from the collection that
are modeled by your Mongoid model class. delete_all
does not run
callbacks.
The following example shows how to use delete_all
to delete all
Person
documents:
Person.delete_all
destroy_all
The destroy_all
method deletes all documents from the collection
that are modeled by your Mongoid model class. This can be an expensive
operation because Mongoid loads all documents into memory.
The following example shows how to use destroy_all
to delete all
Person
documents:
Person.destroy_all
Persistence Attributes
The following sections describe the attributes that Mongoid provides that you can use to check if a document is persisted to the database.
new_record?
The new_record?
attribute returns true
if the model instance is
not saved to the database yet, and false
otherwise. It checks for
the opposite condition as the persisted?
attribute.
The following example shows how to use new_record?
:
person = Person.new( first_name: "Tunde", last_name: "Adebayo" ) puts person.new_record? person.save! puts person.new_record?
true false
persisted?
The persisted?
attribute returns true
if Mongoid persists the
model instance, and false
otherwise. It checks for the opposite
condition as the new_record?
attribute.
The following example shows how to use persisted?
:
person = Person.new( first_name: "Kiana", last_name: "Kahananui" ) puts person.persisted? person.save! puts person.persisted?
false true
Access Field Values
Mongoid provides several ways to access field values on a document. The following sections describe how you can access field values.
Get and Set Field Values
There are multiple ways to get and set field values on a document. If you explicitly
declare a field, you can get and set this field value on the document directly.
The following example shows how to set and get the first_name
field for a
Person
instance:
class Person include Mongoid::Document field :first_name end person = Person.new person.first_name = "Artem" person.first_name # => "Artem"
The preceding example first uses the first_name
attribute to set a
value, then calls it again to retrieve the value.
You can also use the []
and [] =
methods on a Mongoid model instance to
access attributes by using hash syntax. The []
method is an alias
for the read_attribute
method and the [] =
method is an alias
for the write_attribute
method. The following example shows how to
get and set the aliased first_name
field by using the []
and
[]=
methods:
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">
To learn more about these methods, see the following read_attribute and write_attribute section of this guide.
read_attribute and write_attribute
You can use the read_attribute
and write_attribute
methods to specify
custom behavior when reading or writing fields. You can use these methods
when defining a model or by calling them on model instances.
To use read_attribute
to get a field, pass the name of the field to the method.
To use write_attribute
to set a field, pass the name of the field and the
value to assign.
The following example uses read_attribute
and write_attribute
in
a model definition to define first_name
and first_name=
as methods that
are used to read and write to the fn
attribute:
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"
You can also call read_attribute
and write_attribute
directly on a
model instance to get and set attributes. The following example uses these methods
on a model instance to get the first_name
attribute and set it to the value
"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">
Bulk Write Attributes
You can write to multiple fields at the same time by using the attributes=
or write_attributes
methods on a model instance.
To use the attributes=
method, call the method on a model instance and
pass a hash object that contains the fields and values that you want to set.
The following example shows how to use the attributes=
method to set the
first_name
and middle_name
fields on a person
document:
person.attributes = { first_name: "Jean-Baptiste", middle_name: "Emmanuel" }
To use the write_attributes
method, call the method on a model instance
and pass the fields and values that you want to set. The following example
shows how to use the write_attributes
method to set the first_name
and
middle_name
fields on a person
document:
person.write_attributes( first_name: "Jean-Baptiste", middle_name: "Emmanuel", )
Atomic Update Operators
Mongoid provides support for the following update operators that you can call as methods on model instances. These methods perform operations atomically and skip validations and callbacks.
The following table describe the operators supported by Mongoid:
Operator | Description | Example | |||
---|---|---|---|---|---|
| Adds a specified value to an array-valued field. |
| |||
| Performs a bitwise update of a field. |
| |||
| Increments the value of a field. |
| |||
| Removes the first or last element of an array field. |
| |||
| Removes all instances of a value or values that match a specified condition from an array field. |
| |||
| Removes all instances of the specified values from an array field. |
| |||
| Appends a specified value to an array field. |
| |||
| Renames a field in all matching documents. |
| |||
| 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. |
| |||
| Deletes a particular field in all matching documents. |
|
To learn more about update operators, see Update Operators in the MongoDB Server manual.
Group Atomic Operations
To group atomic operations together, you can use the atomically
method
on a model instance. Mongoid sends all operations that you pass to an
atomically
block in a single atomic command.
Note
Use Transactions to Modify Multiple Documents Atomically
Atomic operations apply to one document at a time. Therefore, nested
atomically
blocks cannot make changes to multiple documents in one
atomic operation. To make changes to multiple documents in one atomic
operation, use a multi-document transaction. To learn more about
transactions, see the Transactions and Sessions guide.
The following example shows how to use atomically
to atomically
update multiple fields in a document:
person.atomically do person.inc(age: 1) person.set(name: 'Jake') end
You can nest #atomically
blocks when updating a single document. By
default, Mongoid performs atomic writes defined by each block when the
block ends. The following example shows how to nest atomically
blocks:
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
In the preceding example, the $inc
and $set
operations are executed at
the end of the inner atomically
block.
Join Contexts
The atomically
method accepts a join_context: true
option to specify that
operations execute at the end of the outermost atomically
block. When you
enable this option, only the outermost block, or the first block where join_context
is false
, writes changes to the database. The following example sets
the join_context
option to 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
In the preceding example, Mongoid performs the $inc
and $set
operations at the
end of the outermost atomically
block. However, since an exception is raised
before the block ends and these operations can run, the changes are not
persisted.
You can also enable context joining globally, so that operations execute in the
outermost atomically
block by default. To enable this option
globally, set the join_contexts
configuration option to true
in
your mongoid.yml
file. To learn more about Mongoid configuration
options, see Self-Managed Configuration File Options.
When you globally set join_contexts
to true
, you can use the
join_context: false
option on an atomically
block to run
operations at the end of the block for that block only.
Dirty Tracking
You can track changed ("dirty") fields by using a Mongoid API similar to the one available in Active Model. If you modify a defined field in a model, Mongoid marks the model as dirty and allows you to perform special actions. The following sections describe how you can interact with dirty models.
View Changes
Mongoid records changes from the time a model is instantiated, either as a new document or by retrieving one from the database, until the time it is saved. Any persistence operation clears the changes.
Mongoid creates model-specific methods that allow you to explore the changes to a model instance. The following code demonstrates ways that you can view changes on your model instance:
# 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"
Note
Tracking Changes to Associations
Setting the associations on a document does not modify the
changes
or changed_attributes
hashes. This is true for all
types of associations. However, changing the
_id
field on referenced associations causes the changes to
show up in the changes
and the changed_attributes
hashes.
Reset Changes
You can reset a changed field to its previous value by calling the
reset
method, as shown in the following code:
person = Person.first person.name = "Sarah Frank" # Reset the changed `name` field person.reset_name! person.name # "Sarah Frink"
Persistence
Mongoid uses dirty tracking as the basis of all persistence operations.
It evaluates the changes on a document and atomically updates only what
has changed, compared to other frameworks that write the entire document on
each save. If you don't make any changes, Mongoid does not access the
database when you call Model#save
.
View Previous Changes
After you persist a model to MongoDB, Mongoid clears the current
changes. However, you can still see what changes were made previously by
calling the previous_changes
method, as shown in the following
code:
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" ] }
Update Container Fields
Mongoid currently has an issue that prevents changes to attributes of
container types, such as Set
or Array
, from saving to MongoDB.
You must assign all fields, including container types, for their values
to save to MongoDB.
For example, adding an item to a Set
instance as shown in the
following code does not persist changes to MongoDB:
person = Person.new person.interests # => #<Set: {}> person.interests << 'Hiking' # => #<Set: {"Hiking"}> person.interests # => #<Set: {}> # Change does not take effect
To persist this change, you must modify the field value outside of the model and assign it back to the model as shown in the following code:
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"}>
Read-only Documents
You can mark documents as read-only in the following ways, depending on
the value of the Mongoid.legacy_readonly
feature flag:
If this flag is turned off, you can mark a document as read-only by calling the
readonly!
method on that document. The resulting read-only document raises aReadonlyDocument
error if you attempt to perform any persistence operation, including, but not limited to, saving, updating, deleting, and destroying. Note that reloading does not reset the read-only state.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 If this flag is turned
on
, you can mark a document as read-only after you project that document by using methods such asonly
orwithout
. As a result, you can't delete or destroy the read-only document because Mongoid raises aReadonlyDocument
error, but you can save and update it. The read-only status is reset if you reload the document.person = Person.only(:name).first person.readonly? # => true person.destroy # => raises ReadonlyDocument error person.reload.readonly? # => false Tip
Projection
To learn more about projections, see the Return Specified Fields section of the Modify Query Results guide.
You can also make a document read-only by overriding the readonly?
method, as shown in the following code:
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
Additional Information
To learn more about specifying query filters, see the Specify a Query guide.
To learn more about setting validation rules on your models, see the Document Validation guide.
To learn more about defining callbacks, see the Callbacks guide.