Rails Diary

プログラミングの学習記録です。

PFメモ日記(1) DBからランダムに値を取ってくる

複数ある中からある一つをランダムで出力する機能を作りたい。

課題で作った掲示板アプリの機能を使って以下のメソッドを試してみる。

機能:掲示板に投稿されたコメントの中から一つランダムで出力する

  • sampleメソッド
  • whereメソッド
  • offsetメソッド

sampleメソッド

配列の要素を1個(引数を指定した場合は自身の要素数を超えない範囲でn個)ランダムに選んで返します。クエリ:sample | るりまサーチ

board.comments.all.sample
  Comment Load (0.1ms)  SELECT "comments".* FROM "comments" WHERE "comments"."board_id" = ?  [["board_id", 39]]
=> #<Comment id: 48, body: "卵", user_id: 1, board_id: 39, created_at: "2022-06-10 08:28:18", updated_at: "2022-06-10 08:28:18">
デメリット

処理に時間がかかりすぎるらしい

offsetメソッド

テーブルからデータを取得する際、どのデータから取得するか(取得開始位置)を指定したい場合、offsetメソッドを使います。 【Rails】offsetメソッドで取得するデータの範囲を指定する方法を解説 | CODE MARINE

IT用語辞典

オフセット【offset】
ITの分野では、何かの位置を指し示す際に、基準となる位置からの差(距離、ズレ、相対位置)を表す値のことをオフセットということが多い。オフセットとは - 意味をわかりやすく - IT用語辞典 e-Words

モデル名.offset(2)

↑先頭は0から始まるため(インデックス番号)、引数にはそれに応じた番号を渡している

randメソッド

指定した範囲の中からランダムな値を返す。

board.comments.offset(rand(board.comments.count)).first
   (0.1ms)  SELECT COUNT(*) FROM "comments" WHERE "comments"."board_id" = ?  [["board_id", 39]]
  Comment Load (0.1ms)  SELECT  "comments".* FROM "comments" WHERE "comments"."board_id" = ? ORDER BY "comments"."id" ASC LIMIT ? OFFSET ?  [["board_id", 39], ["LIMIT", 1], ["OFFSET", 1]]
=> #<Comment id: 49, body: "いちご", user_id: 1, board_id: 39, created_at: "2022-06-10 08:28:23", updated_at: "2022-06-10 08:28:23">

whereメソッド

board.comments.where('id >= ?', rand(board.comments.first.id..board.comments.last.id)).first
  Comment Load (0.1ms)  SELECT  "comments".* FROM "comments" WHERE "comments"."board_id" = ? ORDER BY "comments"."id" ASC LIMIT ?  [["board_id", 39], ["LIMIT", 1]]
  Comment Load (0.1ms)  SELECT  "comments".* FROM "comments" WHERE "comments"."board_id" = ? ORDER BY "comments"."id" DESC LIMIT ?  [["board_id", 39], ["LIMIT", 1]]
  Comment Load (0.1ms)  SELECT  "comments".* FROM "comments" WHERE "comments"."board_id" = ? AND (id >= 50) ORDER BY "comments"."id" ASC LIMIT ?  [["board_id", 39], ["LIMIT", 1]]
=> #<Comment id: 50, body: "納豆", user_id: 1, board_id: 39, created_at: "2022-06-10 08:28:28", updated_at: "2022-06-10 08:28:28">
  • id >= ??プレースホルダーと呼ばれており、第二引数で指定した値に置き換えられる
  • 第二引数のrand(board.comments.first.id..board.comments.last.id)で取得した値が?に入る
デメリット

IDに抜けがあるとランダムの正確性に欠ける

まとめ

  • 自分が試した中ではそもそものコメント総数が多くなかったので、大きな速度差がなかった
  • 実際はwhere>offset>>sampleの順に速さが変わるらしい
  • 正確性の面ではoffset>where

参考にしたサイト

https://izanagi-portfolio-site.com/blog/articles/3yg4y3i-ih_e/

【Rails】offsetメソッドで取得するデータの範囲を指定する方法を解説 | CODE MARINE

【Rails】 whereメソッドを使って欲しいデータの取得をしよう! | Pikawaka