【Rails入門】uniqで重複が無いモデルにしよう!distinctにも対応

こんにちは!システムエンジニアのオオイシです。

今回は、Ruby on Railsのuniqメソッドをご存じですか!?

uniqメソッドを使うと、

「重複レコードを1つにまとめて取得」

「SQLのDISTINCTをRailsで実行」

などの課題を解決できます。

そこで今回は以下の内容について解説していきます。

【基礎】uniqメソッドとは?distinctとの違い
【基礎】uniq(distinct)メソッドの構文
【基礎】uniq(distinct)メソッドを使ってみよう!
【応用】uniq(distinct)メソッドの実用的な使い方を紹介

初心者でもわかるように解説していますので、しっかりと理解しておきましょう!

目次

uniqメソッドとは?distinctとの違い

uniqメソッドとは、Railsで取得した重複レコードを1つにまとめるためのメソッドです。

uniqメソッドを実行すると、Railsは内部的にSQLのDISTINCTを実行します。

その他に、uniqメソッドとまったく同じ働きをするdistinctメソッドも存在します。

両者の違いは、

  • uniqメソッド   → Rails5以降で非推奨(または使えなくなる)
  • distinctメソッド → Rails5以降で正式メソッド

となっているので注意しましょう!

そのため、これからはdistinctメソッドを使うようにしてください。

本記事でもdistinctメソッドで解説します。

なお、SQLのDISTINCTについては、こちらで詳しく解説しているため、ぜひ参考にしてください。

uniq(distinct)メソッドの構文

構文は次の通りです。

  • モデル.select(列名).distinct

Railsのログを確認するとこのようなSQLが実行されます。

Railsが実行するSQL:

SELECT S DISTINCT `テーブル名`.`列名` FROM `テーブル名`

次項では、distinctメソッドの使い方を詳しく解説していきます。

uniq(distinct)メソッドを使ってみよう!

ここでは、distinctメソッドの使い方をサンプルコードを使って解説します。

姓(last_name)と名(first_name)のカラムをもつSampleモデルを作成し、distinctメソッドの動きを確認してみましょう。

サンプルモデルの作成

はじめに、Sampleモデルを作成します。

$ bin/rails g model sample last_name:string first_name:string
Running via Spring preloader in process 19028
      invoke  active_record
      create    db/migrate/20180826112329_create_samples.rb
      create    app/models/sample.rb
$ bin/rake db:migrate

rails コンソールでテストデータを投入します。

$ bin/rails c
> Sample.create!(last_name: "侍", first_name: "太郎")
> Sample.create!(last_name: "侍", first_name: "次郎")
> Sample.create!(last_name: "侍", first_name: "花子")
> Sample.create!(last_name: "侍", first_name: "太郎")
> Sample.all
+----+-----------+------------+-------------------------+-------------------------+
| id | last_name | first_name | created_at              | updated_at              |
+----+-----------+------------+-------------------------+-------------------------+
| 1  | 侍        | 太郎       | 2018-08-27 06:15:04 UTC | 2018-08-27 06:15:04 UTC |
| 2  | 侍        | 次郎       | 2018-08-27 06:15:35 UTC | 2018-08-27 06:15:35 UTC |
| 3  | 侍        | 花子       | 2018-08-27 06:15:43 UTC | 2018-08-27 06:15:43 UTC |
| 4  | 侍        | 太郎       | 2018-08-27 06:15:47 UTC | 2018-08-27 06:15:47 UTC |
+----+-----------+------------+-------------------------+-------------------------+
4 rows in set

登録したサンプルデータを使って、distinctメソッドを使ってみましょう。

なお、RailsコンソールでActive Recordの検索結果を一覧で確認できるようにするために、HirbというGemを使っています。

こちらに解説があるので参考にしてみてください。

Railsのモデルについてはこちらで詳しく解説しています。

uniq(distinct)メソッドの使い方

準備が整いましたので、distinctメソッドを使って、姓(last_name)の重複をまとめて表示するサンプルコードを見てみましょう。

使い方はとっても簡単です!

distinctを使わない場合:

> Sample.select(:last_name)
  Sample Load (1.3ms)  SELECT `samples`.`last_name` FROM `samples`
+----+-----------+
| id | last_name |
+----+-----------+
|    | 侍        |
|    | 侍        |
|    | 侍        |
|    | 侍        |
+----+-----------+
4 rows in set

distinctを使う場合:

> Sample.select(:last_name).distinct
  Sample Load (0.8ms)  SELECT DISTINCT `samples`.`last_name` FROM `samples`
+----+-----------+
| id | last_name |
+----+-----------+
|    | 侍        |
+----+-----------+
1 row in set
irb(main):006:0>

このように、重複がないレコードが取得できました。

次項では、distinctメソッドの応用的な使いかたを紹介していきます!

uniq(distinct)メソッドの実用的な使い方を紹介

複数列でdistinctメソッドを使う

複数の列を指定してdistinctした場合には、複数列を合わせてユニークになるように重複がまとめられます。

  • モデル.select(列名,列名…).distinct

姓(last_name)と名(first_name)の2列に対してdistinctするサンプルコードを確認して見ましょう。

distinctを使わない場合:

> Sample.select(:last_name,:first_name)
  Sample Load (0.5ms)  SELECT `samples`.`last_name`, `samples`.`first_name` FROM `samples`
+----+-----------+------------+
| id | last_name | first_name |
+----+-----------+------------+
|    | 侍        | 太郎       |
|    | 侍        | 次郎       |
|    | 侍        | 花子       |
|    | 侍        | 太郎       |
+----+-----------+------------+
4 rows in set

distinctを使う場合:

> Sample.select(:last_name,:first_name).distinct
  Sample Load (0.7ms)  SELECT DISTINCT `samples`.`last_name`, `samples`.`first_name` FROM `samples`
+----+-----------+------------+
| id | last_name | first_name |
+----+-----------+------------+
|    | 侍        | 太郎       |
|    | 侍        | 次郎       |
|    | 侍        | 花子       |
+----+-----------+------------+
3 rows in set

このように、複数列で重複のないレコードを取得することができました。

distinctして件数を調べるには

distinctを使ってレコード件数を数える方法について紹介します。

モデルのデータ件数を数えるためにsizeメソッドがありますが、これを組み合わせて件数を取得します。

  • モデル.select(列名,列名…).distinct.size

重複のない姓(last_name)の件数を調べる、サンプルコードを確認して見ましょう。

distinctを使わない場合:

> Sample.select(:last_name).size
   (0.2ms)  SELECT COUNT(*) FROM `samples`
=> 4

distinctを使う場合:

> Sample.select(:last_name).distinct.size
   (0.6ms)  SELECT COUNT(*) FROM (SELECT DISTINCT `samples`.`last_name` FROM `samples`) subquery_for_count
=> 1

このように、レコードの件数を数えることができました。

rubyの配列にはuniqメソッドを使う

Rubyの配列には、重複を1つにまとめるuniqメソッドがあるため、こちらも紹介します。

姓(last_name)のレコードを配列で取得して、uniqメソッドで重複のない配列を取得するサンプルコードを確認して見ましょう。

uniqを使わない場合:

> Sample.pluck(:last_name)
   (0.4ms)  SELECT `samples`.`last_name` FROM `samples`
=> ["侍", "侍", "侍", "侍"]

uniqを使う場合:

> Sample.pluck(:last_name).uniq
       (0.3ms)  SELECT `samples`.`last_name` FROM `samples`
=> ["侍"]

このように重複のない配列を取得することができました。

なお、pluckの使い方については、こちらで詳しく解説しているのでぜひ参考にしてください。

まとめ

いかかでしたか?

今回は、Railsのuniq(distinct)メソッドの使い方をについて解説しました。

uniq(distinct)メソッドは、Railsで取得した重複レコードを1つにまとめるためのメソッドです。

uniq(distinct)メソッドを使うと、Rails内部ではSQLのDISTINCTが実行されるため、何かと利用頻度の多いメソッドです。

uniq(distinct)メソッドの使い方を忘れてしまったらこの記事を確認してくださいね!

この記事を書いた人

システムエンジニア歴15年のオオイシです!好物は Java と Ruby。プログラミング、システムアーキテクトからマネジメントに到るまでなんでも食べます。
システム開発の相談やお困りごとがあればお気軽に
makoto.oishi.0705@gmail.com まで連絡頂けると幸いです

目次