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/