Morad Edwar
Morad Edwar

Reputation: 1050

How do duplicate/clone ActiveRecord::Relation in optimized way

I want to clone a list of ActiveRecord objects in an optimized way. Maybe the way that I am using is optimized already but I need to speed up this process. So this is my code

ActiveRecord::Base.transaction do
  data = MyModel.where(column_1: 'x')
  data.each do |item|
    new_item = item.dup
    new_item.column_2 = 'y'
    new_item.save!
  end
end

Maybe there is a better way of duplicating a list of records at once then update all of them with one query. I tried to Google it but no luck till now.

Upvotes: 0

Views: 732

Answers (3)

Ben Trewern
Ben Trewern

Reputation: 1740

If you want to do this as quickly as possible then SQL is the way to go.

Something like this would do it:

ActiveRecord::Base.connection.execute <<-SQL
   INSERT INTO my_models (column_1, column_2, column_3, ..)
      SELECT column_1, 'y', column_3, ..
      FROM my_models WHERE column_1 = 'x';
SQL

This should work in PostgreSQL and MySql.

If you have any rails magic columns (created_at, updated_at etc) they will have to be added manually in the SQL.

Upvotes: 0

Morad Edwar
Morad Edwar

Reputation: 1050

Short answer is to use single insert statement instead of multiple inserts even though if it's in one DB transaction.

And bulk_insert gem will help you to do it. ( Thanks to arieljuod )

Upvotes: 0

Yurii Verbytskyi
Yurii Verbytskyi

Reputation: 2052

If I understood right, you want to duplicate objects that meet condition

(column_1: 'x')

You can try this approach, looks like it will do the same

MyModel.where(column_1: 'x').find_each { |u| u.dup.update(column2: 'y') }

But a little slower(benchmarked n = 1000)

<Benchmark::Tms:0x00007f96e6a1b970 @label="**dup.update**", @real=6.75463099999979, @cstime=0.0, @cutime=0.0, @stime=0.331546, @utime=2.2468139999999996, @total=2.5783599999999995>,

<Benchmark::Tms:0x00007f96e8cb23f8 @label="**dup.save!**", @real=6.470054999999775, @cstime=0.0, @cutime=0.0, @stime=0.32828900000000005, @utime=1.972385, @total=2.300674>

Upvotes: 1

Related Questions