LoginSignup
15
16

More than 5 years have passed since last update.

Railsで重複レコードを一気に削除する方法

Last updated at Posted at 2018-06-24

環境

rails 5.1.4
ruby 2.5.0

背景

Railsでリリース前のアプリを作っていて、Tagモデルに後からunique制約を入れたのですが、元々のデータで重複がたくさんあり、それを消す時にどうすればいいか悩みました。

最初は下記の記事を参考に削除しようとしたのですが、created_atが重複して完全には消せなかったので、IDをキーに削除しました。IDをキーで消したい人の参考になれば。それ以外のキーで消したい場合は、下記記事を参考ください。

【Ruby on Rails】重複しているレコードを取得する【MySQL】
http://techblog.kyamanak.com/entry/2017/10/18/215532

方法

まずは下記のコードで重複がどれだけあるか確認。今回はTagモデルのnameの重複を確認します。

そうすると重複しているレコードがズラズラ出て来ます。

pry(main)> Tag.group(:name).count.sort_by(&:second).reverse
=> [["aaa", 4],
 ["bbb", 3],
 ["ccc", 2],
 ["ddd", 2],
 ["eee", 2],
etc...

順調に重複しているのがわかると思います。

方針としては上記記事にもある通り下記の方針で削除します。
・重複しているレコードの中で、残したいレコードのIDを取得する。
・重複しているレコードの中で、残したいレコード以外を削除する。

その中で上記記事ではcreated_atを基準に削除されていました。
しかし私の場合は、created_atが被っていた為、削除ができませんでした。

そのためIDをキーに削除することにしました。
IDをキーにすると書くコードを一つ少なくすることができます。

結論的には下記で消すことができます。

pry(main)> hash = Tag.group(:name).having('count(*) >= 2').maximum(:id)
=> {"aaa"=>2202,
 "bbb"=>3361,
 "ccc"=>2699,
 "ddd"=>3960,
 "eee"=>2212,
etc...

pry(main)> Tag.where(name: hash.keys).where.not(id: hash.values).destroy_all

最後に消せたかどうかを確認すると、

pry(main)> Tag.group(:name).count.sort_by(&:second).reverse
=> [["aaa", 1],
 ["bbb", 1],
 ["ccc", 1],
 ["ddd", 1],
 ["eee", 1],
etc...

で消せたことが確認できました。

15
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
16