picardo
picardo

Reputation: 24896

How do I update a cumulative field in a Rails database (using ActiveRecord or Mongoid)?

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

Answers (1)

ches
ches

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

Related Questions