旧ブログ(ISSEN)から移行しました

【Rails】where.missingを使用して手軽に関連先のないレコードを取得する方法

【Rails】where.missingを使用して手軽に関連先のないレコードを取得する方法

塩見直樹
塩見直樹3分で読めます

はじめに

こんにちは、株式会社TOKOSのナオキです!
今回はRailsのwhere.missingを使用して関連先のないレコードを取得する方法を解説します!

この記事では以下の内容について取り上げています

  • where.missingの概要
  • where.missingの基本的な使用方法
  • SQLクエリについて

対象読者

  • Rails初学者の方
  • Railsで開発を行っている方

where.missingの概要

where.missingはRails 6.1で追加されたActiveRecordメソッドです。
関連先がないレコードを手軽に取得できます!

例えば、投稿モデル(Post)とコメントモデル(Comment)が一体多の関係である場合、
Postに関連するCommentが存在しない投稿(コメントの存在しない投稿)を取得できます。
開発をしていると条件分岐等で、関連先がないレコードを取得したいときは結構あると思います。
そのようなときにwhere.missingを知っていると、簡潔にコードを書くことができます!
今回は説明を省きますが、where.associatedというwhere.missingと逆の意味である、関連先が存在するレコードのみを取得できるメソッドもあります!

where.missingの基本的な使用方法

基本的な使用方法

基本的な使用方法として「コメントのない投稿」を取得する方法を紹介します。

Ruby
Post.where.missing(:comments)

これだけの記述でコメントのない投稿を取得できちゃいます!
where.missingがでる前は下記のようにleft_joinswhereを組み合わせて取得していました。

Ruby
Post.left_joins(:comments).where(comments: { id: nil })

上記の2つのコードを比べてみるとleft_joinswhereを使用している方は、冗長なコードになってしまっています。
where.missingを知っているだけでこのように簡潔にコードを書くことができます!

複数の関連先がないレコード取得

例えば「コメント(comment)もいいね(like)もない投稿」を取得する場合に、下記のコードのように複数のwhere.missingを組み合わせて取得できます!

Ruby
Post.where.missing(:comments).where.missing(:likes)

上記のコードをwhere.missingを使用しないと下記のようになります。

Ruby
Post.left_joins(:comments).left_joins(:likes).where(comments: { id: nil }, likes: { id: nil })

こうやって見比べるとコードがスッキリとしているのが一目瞭然ですね!

SQLクエリについて

SQLクエリの詳細

where.missingが生成するSQLはLEFT OUTER JOINを使用して、関連先のデータがNULLの行を取得します。
これにより関連先のないデータを取得できています!

例としてPost.where.missing(:comments)が生成するSQLクエリは下記のようになります。

SQL
SELECT "posts".* FROM "posts"
LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id"
WHERE "comments"."id" IS NULL

実はwhere.missingを使用しても、left_joinswhereを組み合わせたものを使用しても同じSQLが生成されます!

さいごに

今回はRailsのwhere.missingについて解説しました。
開発を方は、関連先のないレコードを取得する場面があるかと思います。
そんなときwhere.missingを知っていると、コードを簡潔に書くこともでき可読性も上げることができます。
なのでそのような場面に出会したら積極的に使っていきたいですね!

この記事を書いた人

塩見直樹
塩見直樹

TOKOSのバックエンドエンジニア。パフォーマンス最適化と可読性の向上を目指しています。アニメ好きで、特にHUNTER×HUNTERが好きです。