railsで1対多が複数ある場合のリレーションで関連テーブルのデータも取得する

rails

本記事では、1対多の関係があるテーブルの多側がさらに1対多の関係を持っている場合のデータ取得方法について解説していこうと思います。

今回、考えるのは下記のような構造。youtubeにおける、youtuber>video>commentの関係を示しています。

youtuberは複数の動画(video)を投稿しており、動画には複数のcommentがついています。本記事では、youtuberに紐づいているすべてのvideoに紐づいているコメントを全件取得する方法として、youtuberごとにハッシュでまとめる方法と、youtuber_idに紐づいたコメントを全件取得する方法について解説します。

どういうデータ構造を想定しているか

  • youtuberごとにハッシュでまとめる方法
youtuber
  { id: 1  # youtuber idは特定のもののみ
    videos{
        id: 1
        comments: {
           id: 1,
           id: 2,
           id: 3
        }
        id: 2
        comments: {
           id: 1,
           id: 2,
           id: 3
        }
        id: 3
        comments: {
           id: 1,
           id: 2,
           id: 3
           }
    videos{
        id: 2
        ......
  • 紐づいたコメントを全件取得する方法
# 取得しているデータはcommentが紐づいているvideoを投稿したyoutuberが指定したIDのyoutuberだった場合の
# commentを全件取得する
comment
  {
    id: 1
    text: ...
  },
  {
    id: 3
    text: ...
  }
  {
    id: 8
    text: ...
  }

どちらの方法でも、とあるyoutuberが投稿した動画のコメントを全件取得することに違いはありませんが、データの取り方に違いがあります。

それぞれのデータの取り方によって、下記の画面を実現できます。

  • youtuberごとにハッシュでまとめる方法

この取り方では、videoごとにcommentを取得することができるため、videoごとにデータをまとめたい場合に便利な使い方ができます。youtubeにおける動画再生ページではこのような形式でデータを取得していると思われます。

  • 紐づいたコメントを全件取得する方法

紐づいたコメントのみ取得する場合では、上記のようにvideo_idに関わらずコメントを取得できます。こちらのメリットは、例えばyoutuberの動画に関するすべてのコメントに対していいね数で並び替えたり、新着順にすることができ、全体からのコメントの探索がしやすくなります。

それぞれ、目的に応じたデータ取得方法を実施することで、ウェブアプリの実装の幅が広がります。

1対多(対多)構造の、関連するテーブルを取得する方法

youtuberごとにハッシュでまとめる方法

def youtuber_comments
  youtuber = Youtuber.includes(videos: :comments)
  ...
end

youtuberごとにハッシュでまとめるのは割と簡単で、上記のようにincludesメソッドを紐づければリレーションを取得できます。includes(“子テーブル”: :”孫テーブル”)で取得することができます。

紐づいたコメントを全件取得する方法

def youtuber_comments
  video_ids = Youtuber.find(params[:id]).videos.pluck(:id) # params[:id]は受け取ったyoutuberのid
  comments = Comment.where(video_id: video_ids)  
end

このように、まずは、youtuberが投稿している動画のidの一覧を取得します。

まず、Youtuber.find(params[:id])で、params[:id]は指定したyoutuberのidを受け取ったもので、指定した一人のyoutuberを選択している状態です。そのインスタンスに対して.videosを実行することで、youtuberが投稿した動画の一覧を取得できます。最後にpluck(:id)で、取得したvideosのidのみ受け取ります。videos_idsの結果は下記のようになります。

# video_idsの結果。youtuberが投稿した動画全てのIDを取得している
[3,4,8,...]

その後、Commentモデルに対して、video_idがvideos_idsに当てはまるものを取得することで、youtuberが投稿した全ての動画のコメントを取得できるようになります。

複雑なリレーションのテーブル取得まとめ

以上、複雑なリレーションのテーブル取得方法について解説しました。

リレーションが複雑になると、取得する方法も複雑になります。ただ、ベースの形状をしっかり覚えておけば応用にも対応できると思うので、ベースパターンを経験して、どういうデータを取りたいか、そのデータを取得するためにはどういう処理を書くべきかがすぐ頭で想像して実装できるようになっていきたいです。

コメント

タイトルとURLをコピーしました