Reputation: 24896
I want to update a field in a database table that has to have a cumulative value. So basically I need to find the current value of the field and update it using a new number.
My first inefficient try at this (in Mongoid) is:
v = Landlord.where(:name=>"Lorem")
v.update_attributes(:violations=>v.violations + 10)
Is there a simple method than making one query to read, then sum up, and another query to write?
Upvotes: 1
Views: 166
Reputation: 6622
MongoDB provides special atomic update operation support for exactly this scenario -- take a look at the $inc
modifier in the Updating documentation. Your example in the plain mongo
console would be:
db.landlords.update( { name:"Lorem" }, { $inc: { violations : 10 } } );
With Mongoid this would be:
Landlord.where(:name => "Lorem").first.inc(:violations, 10)
This will set violations to 10 if the field is defined on your model but hasn't otherwise been initialized to any value yet.
But actually, this still executes two queries (look up the landlord, then update it). To do it all in one, you need to go through a Mongoid::Collection
object, which proxies most calls straight through to the Mongo Ruby driver. That would look like this:
Landlord.collection.update({ :name => "Lorem" }, '$inc' => { :violations => 10 })
It helps to be familiar with the Ruby driver for cases like this when you want to take more direct control. Its API tries to match closely with the mongo
Javascript shell syntax.
Upvotes: 1