23

I need to insert a array of emails as different records into my contacts table. How can this be done.

Eg: @email = ["[email protected]", "[email protected]", "[email protected]", ... ]

I dont want to use.

  @email.each do |email|
     @contact = Contact.new
     @contact.email = email
     @contact.save
  end

This cause n insert quires. I just need a single insert query to insert these values. How can this be done in rails 3.0.9 (and ideally MySQL). Please help

1

4 Answers 4

51

activerecord-import implements AR#import

activerecord-import is a library for bulk inserting data using ActiveRecord.

see how it works:

books = []
10.times do |i| 
  books << Book.new(:name => "book #{i}")
end
Book.import books

Project's home is on Github and it's wiki.

Sign up to request clarification or add additional context in comments.

14 Comments

Speeds up a bulk insert significantly.
Also, related question: stackoverflow.com/questions/13718013/…, see the second answer (not the accepted one). The raw SQL version does return all the ids.
And I've got a fork of the gem that not only does that, but automagically efficiently saves any subobjects and their children as well, so that you don't have to maintain parallel sets of arrays to save more complex objects. See here: github.com/GoodMeasuresLLC/activerecord-import
I successfully used this gem to reduce a 260k row data migration from 1 hour down to 6 minutes. Using Postgres.
This is fine. Thanks for the answer.. But, I would like to have this feature for a Model-less table in rails. Is that Possible..?? I am stuck at Model.import. I do not have Model here. Also, I can not create an empty model for this table. That is the situation. Please dont ask me why..
|
4

You might also try upsert, which is approximately as fast as activerecord-import, but only works (currently) with MySQL, Postgres, and SQLite3:

require 'upsert'
Upsert.batch(Contact.connection, Contact.table_name) do |upsert|
  emails.each do |email|
    upsert.row(email: email)
  end
end

Note that this involves one database query per record, but it's an "upsert," so you don't have to check if a record already exists. In your example, this isn't a concern, but in most applications it becomes one eventually.

3 Comments

Having one database query per record is exactly NOT bulk import. Bulk import is having one insert SQL statement with many parameter sets bound to it, so that you have only one database round trip, and hence it's fast.
upsert library started out using INSERT ON DUPLICATE KEY UPDATE, which is bulk.
(oops, hit enter before i could fully explain myself) even though it doesn't do that anymore, it makes 1 trip to the db per record, i think that historical fact is why i unthinkingly didn't justify how upsert is, in my opinion, a form of bulk update. i would define bulk update as "setting new state across many records without regard to their current state" - how many db trips that takes is an (important) detail. "upserting" is a particular way of doing bulk. see github.com/seamusabshere/upsert/commit/b8365d91fe68e450382119 for why i stopped using the 1-trip-per-batch method.
4

The simplest way without additional gem is to concat a string and execute it in one SQL insertion (http://www.electrictoolbox.com/mysql-insert-multiple-records/).

@email = ["[email protected]", "[email protected]", "[email protected]"]

time = Time.current.to_s(:db)

values = @email.map do |email|
  "('#{email}', '#{time}', '#{time}')"
end

sql = "INSERT INTO contacts (email, created_at, updated_at) VALUES #{values.join(', ')}"
Contact.connection.execute(sql)

1 Comment

I implemented this, but now I'm wondering if it's at risk of SQL injection if you are using something a bit more free form than an email.
1

I just wrote a little monkey-patch for Active Record 3.2 to INSERT many new records with a single SQL query, check it out:

https://github.com/alexdowad/showcase/blob/master/activerecord/bulk_db_operations.rb

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.