Along with traditional updates (i.e. replacing an entire document), MongoDB supports atomic, in-place updates with modifier operations, allowing you to update existing values for a document.
Let’s start with a simple Page model:
class Page
include MongoMapper::Document
key :title, String
key :day_count, Integer, :default => 0
key :week_count, Integer, :default => 0
key :month_count, Integer, :default => 0
key :tags, Array
end
The atomic modifier operations can be performed directly on instances of your MongoMapper class, or on a collection by passing in the ID (s) or criteria of the documents you wish to modify.
Increment the given keys by the values specified.
@page.increment(:day_count => 1, :week_count => 2, :month_count => 3)
Page.increment({:title => 'Home'}, :day_count => 1, :week_count => 2, :month_count => 3)
Page.increment(@page.id, @page2.id, :day_count => 1, :week_count => 2, :month_count => 3)
Decrement the given keys by the values specified.
@page.decrement(:day_count => 1, :week_count => 2, :month_count => 3)
Page.decrement({:title => 'Home'}, :day_count => 1, :week_count => 2, :month_count => 3)
Page.decrement(@page.id, @page2.id, :day_count => 1, :week_count => 2, :month_count => 3)
Set the values for the keys.
@page.set(:title => "New Home")
Page.set({:title => 'Home'}, :title => "New Home")
Page.set(@page.id, @page2.id, :title => "New Home")
Unset or remove the given keys.
@page.unset(:title)
Page.unset({:title => 'Home'}, :title)
Page.unset(@page.id, @page2.id, :title)
Append one value to the array key.
@page.push(:tags => 'foo')
Page.push({:title => 'Home'}, :tags => 'foo')
Page.push(@page.id, @page2.id, :tags => 'foo')
Append several values to the array key.
@page.push_all(:tags => ['foo','bar'])
Page.push_all({:title => 'Home'}, :tags => ['foo','bar'])
Page.push_all(@page.id, @page2.id, :tags => ['foo','bar'])
Append one unique value to the array key.
@page.add_to_set(:tags => 'foo')
Page.add_to_set({:title => 'Home'}, :tags => 'foo')
Page.add_to_set(@page.id, @page2.id, :tags => 'foo')
Remove one value from the array key.
@page.pull(:tags => 'foo')
Page.pull({:title => 'Home'}, :tags => 'foo')
Page.pull(@page.id, @page2.id, :tags => 'foo')
Remove several values from the array key.
@page.pull_all(:tags => ['foo','bar'])
Page.pull_all({:title => 'Home'}, :tags => ['foo','bar'])
Page.pull_all(@page.id, @page2.id, :tags => ['foo','bar'])
Remove the last element from the array key.
@page.pop(:tags => 1)
Page.pop({:title => 'Home'}, :tags => 1)
Page.pop(@page.id, @page2.id, :tags => 1)
Note that if you pass -1, it will remove the first element from the array.
An options hash can be passed as the final argument. These options will be passed to the Ruby driver’s update method.
For example, even though a model’s safe setting will not apply to modifier operations, atomic updates can still be safe:
@page.increment({:day_count => 1}, :safe => true)
Page.increment({:title => 'Home'}, {:day_count => 1}, :safe => true)
Page.increment(@page.id, @page2.id, {:day_count => 1}, :safe => true)
Or, to do an upsert:
Page.increment({:title => 'Home'}, {:day_count => 1}, :upsert => true)
Please note that MongoMapper always sets the :multi
option to true
. This cannot be overridden.
When applying a modifier operation on a variable (local or instance), make sure to reload the variable. MongoMapper does not update the state of the variable unless you explicitly tell it to like so:
@page.set(:title => "Something New")
@page.title # => "Something Old"
@page.reload
@page.title # => "Something New"