Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create if record does not exist

I have 3 models in my rails app

class Contact < ActiveRecord::Base   belongs_to :survey, counter_cache: :contact_count   belongs_to :voter   has_many :contact_attempts end  class Survey < ActiveRecord::Base   has_many :questions   has_many :contacts end  class Voter < ActiveRecord::Base   has_many :contacts end 

the Contact consists of the voter_id and a survey_id. The Logic of my app is that a there can only be one contact for a voter in any given survey.

right now I am using the following code to enforce this logic. I query the contacts table for records matching the given voter_id and survey_id. if does not exist then it is created. otherwise it does nothing.

if !Contact.exists?(:survey_id => survey, :voter_id => voter)    c = Contact.new    c.survey_id = survey    c.voter_id = voter    c.save end 

Obviously this requires a select and a insert query to create 1 potential contact. When I am adding potentially thousands of contacts at once.

Right now I'm using Resque to allow this run in the background and away from the ui thread. What can I do to speed this up, and make it more efficient?

like image 782
gsueagle2008 Avatar asked Feb 12 '14 04:02

gsueagle2008


People also ask

How do you insert if row does not exist?

There are three ways you can perform an “insert if not exists” query in MySQL: Using the INSERT IGNORE statement. Using the ON DUPLICATE KEY UPDATE clause. Or using the REPLACE statement.

What is if not exists in MySQL?

The clause “if not exists” is used for the creation of tables and is very useful for avoiding the error “table already exists”, as it will not create a table if, in the database, any table is already available by the name of the new table.


2 Answers

You can do the following:

Contact.where(survey_id: survey,voter_id: voter).first_or_create 
like image 66
bazinga012 Avatar answered Oct 05 '22 16:10

bazinga012


You should add first a database index to force this condition at the lowest level as possible:

add_index :contacts, [:voter_id, :survey_id], unique: true 

Then you should add an uniqueness validation at an ActiveRecord level:

validates_uniqueness_of :voter_id, scope: [:survey_id] 

Then contact.save will return false if a contact exists for a specified voter and survey.

UPDATE: If you create the index, then the uniqueness validation will run pretty fast.

like image 44
Nicolas Garnil Avatar answered Oct 05 '22 16:10

Nicolas Garnil