背景
- Railsで検索フォームを作っています
- お手本のコードに読み慣れないメソッドがいっぱい&SQL自体慣れていないので、勉強しながらノートにまとめてみました
▼環境
- Rails 5.2.3
- Ruby 2.6.0
なお、本記事は下記の記事の内容を自分の環境で試しながら、知見をまとめたものです。
distinctメソッド
distinct
メソッドは、レコードを一位にまとめてくれるメソッドです。APIドキュメントはこちら。
例えば、User
がPost
を投稿するアプリにおいて、
> Post.select(:user_id)
とすると、
Post Load (1.2ms) SELECT `posts`.`user_id` FROM `posts`
=> [#<Post:0x00007f826d51c290 id: nil, user_id: 1>,
#<Post:0x00007f826d51c150 id: nil, user_id: 1>,
#<Post:0x00007f826d51c010 id: nil, user_id: 2>,
#<Post:0x00007f826d527e88 id: nil, user_id: 2>,
#<Post:0x00007f826d527d48 id: nil, user_id: 3>,
#<Post:0x00007f826d527c08 id: nil, user_id: 4>,
#<Post:0x00007f826d527ac8 id: nil, user_id: 5>,
#<Post:0x00007f826d527988 id: nil, user_id: 5>]
と出てきます。これにdistinct
を加えると
> Post.select(:user_id).distinct
Post Load (1.6ms) SELECT DISTINCT `posts`.`user_id` FROM `posts`
=> [#<Post:0x00007f8268b1f8e0 id: nil, user_id: 1>,
#<Post:0x00007f826d51c010 id: nil, user_id: 2>,
#<Post:0x00007f826d527d48 id: nil, user_id: 3>,
#<Post:0x00007f826d527c08 id: nil, user_id: 4>,
#<Post:0x00007f826d527988 id: nil, user_id: 5>]
と、投稿がselect
で選択した項目によって一意になります。ちなみに、先の記事にもありますが。select
と一緒に使わないと、全てのpost
をとってきます。
> Post.distinct(:user_id)
SELECT DISTINCT `posts`.* FROM `posts`
/* 全てのpostが表示される */
発行されるSQLを見比べればわかるのですが、
/* selectがある時 */
> Post.select(:user_id).distinct
Post Load (1.6ms) SELECT DISTINCT `posts`.`user_id` FROM `posts`
/* selectがない時 */
> Post.distinct(:user_id)
SELECT DISTINCT `posts`.* FROM `posts`
select
がないと、全てのカラムを持ってきて、それらについて一意の値を呼び出してくるのですね。
逆に「重複する投稿を表示しない」などでしたら、シンプルに
> Post.distinct
SELECT DISTINCT `posts`.* FROM `posts`
で良さそうです。
なお、親子関係のあるレコード(例えばpostのコメント)に関しては、
> post = Post.first
> post.comments.select(:user_id).distinct
/* ある投稿に紐づくコメントについて、user_idが一意のレコードを取得する */
こんな感じで指定ができるようです!