Railsで一括でデータを更新する
はじめに
Railsでデータを大量に追加した場合には効率を考えると1つのSQLでインポートしたいときがあります。
そんな時はactiverecord-importを使っていました。
update_allを使えば特定のレコードに対して同じ値で一括更新することは可能です。では、各レコードに対してそれぞれ異なる値を一括で更新したい場合はどうすれば良いでしょうか?
activerecord-importで一括アップデート
正解はactiverecord-importを使うでした。具体的な方法は公式のWiKiにも記載されています。
On Duplicate Key Update · zdennis/activerecord-import Wiki
これははデータベースの仕組みを使って一括アップデートをサポートしているため、データバースの種類やバージョンに依存します。PostgreSQLだと9.5以上になります。
一括更新した場合のコードは次のとおりです。1つ目の引数で更新したいオブジェクトのコレクションを渡します。on_duplicate_key_update/conflict_targetでDB上で一意制約が指定されているカラムを指定します。Railsだとidとなることが多いと思います。on_duplicate_key_update/columnsで更新したいカラムを指定します。
上記のコードを実行すると次のようなSQLが発行されます。
発行されるのはupdateではなくてinsertになります。
特に注目すべき箇所は次の箇所です。
今回のコードではon_duplicate_key_update/conflict_targetで指定したidは既に存在しているため通常はinsertが行われると一意制約によってコンフリクトが発生します。
しかし、このSQLではコンフリクトが発生した場合には、例外ではなく同じidのtitleを更新するようになります。
まとめ
個人的にはBulk InsertとかBulk UpdateはSQLでは昔からあるので、Railsの標準機能になってほしい気持ちもあります。
特に大量データの更新の場合には利用してみてください。
Let’s enjoy Rails!