Rails 6の標準機能ででbulk importする

公開:2020/12/27
更新:2020/12/27
2 min読了の目安(約2000字TECH技術記事

bulk importするならactiverecord-importが定番です。
でも、Rails 6でもbulk importおよびBulk Upsertできます。

test用repository

下記でinsert_allとupsert_allでUserをimportおよびupsertを試すことができます。

rails db:migrate
rails db:seed

Bulk import例

ActiveRecordのattirbutesのHashのArrayを引数として insert_all! 特異methodを呼び出します。

insert_all
insert_all!

User modelはこんな感じ。

# frozen_string_literal: true

# == Schema Information
#
# Table name: users
#
#  id         :integer          not null, primary key
#  email      :string           not null
#  name       :string           not null
#  created_at :datetime         not null
#  updated_at :datetime         not null
#
# Indexes
#
#  index_users_on_email  (email) UNIQUE
#
class User < ApplicationRecord
  has_many :posts
  has_many :comments
end

10個のUserをBulk importします。

require 'faker'

### Example of bulk insert
def user_params
  time = Faker::Time.backward
  {
    name: Faker::Name.name,
    email: Faker::Internet.email,
    created_at: time,
    updated_at: time
  }
end

User.insert_all!(10.times.map { user_params })
pp User.count
#=> 10

Bulk Upsert例

Upsertもできます。Upsertする場合は uniq制約がついたカラムが必要です。
今回の例ではemail が uniq制約ついています。

upsert_all

emailが重複する場合は update、emailが重複しない場合はinsertします。


### Example of Upsert
user = User.first
list = [
  {
    email: user.email,
    name: 'hoge',
    created_at: user.created_at,
    updated_at: Time.now
  },
  {
    email: 'fuga@fuga.co.jp',
    name: 'fuga',
    created_at: Time.now,
    updated_at: Time.now,
  }
]

User.upsert_all(list, unique_by: :email)

pp User.count
#=> 11

activerecord-imprtより便利!ということはないのだけど、多くの用途では十分だし、プロジェクトによってはactiverecord-importが入っていないばあいは、標準機能だけで bulk importできるのは覚えておくと重宝します。