kasei_sanのブログ

かせいさんのIT系のおぼえがきです。胡乱の方はnoteとtwitterへ

Railsガイド Active Record クエリインターフェイス:1.データベースからオブジェクトを取り出す

Active Record クエリインターフェイス | Rails ガイド

Model.find(options)という操作を要約すると以下のようになります。

与えられたオプションを同等のSQLクエリに変換します。
SQLクエリを発行し、該当する結果をデータベースから取り出します。
得られた結果を行ごとに同等のRubyオブジェクトとしてインスタンス化します。
指定されていれば、after_findを実行し、続いてafter_initializeコールバックを実行します。

find

idで検索 - 見つからない場合、ActiveRecord::RecordNotFound例外が発生

Client.find(10)
SELECT * FROM clients WHERE (clients.id = 10) LIMIT 1

複数のキーを同時に検索

1つでもマッチしないと、ActiveRecord::RecordNotFound例外が発生

Client.find([1, 10])
SELECT * FROM clients WHERE (clients.id IN (1,10))

find のオプション

Rails4で廃止 - 検索条件を指定したい場合は、#where を使うこと

take,first,last

  • レコードを1つ取り出す
  • 引数でn個取り出せる
  • #first は主キーで昇順ソートする
  • #last は主キーで降順ソートする

レコードがない場合

Client.take
Client.first
Client.last
SELECT * FROM clients LIMIT 1
SELECT * FROM clients ORDER BY clients.id ASC LIMIT 1
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1

LIMITの数を指定する

Client.take(10)

find_by

条件を満たす最初のレコードを返す

Client.find_by(first_name: 'Lifo')
Client.where(first_name: 'Lifo').take # 同じ意味
SELECT * FROM clients WHERE (clients.first_name = 'Lifo') LIMIT 1

レコードがない場合

複数のオブジェクトをバッチで取り出す

User.all.each とかやると全レコードをまとめてメモリに入れるので死ぬ

通常やり方は2通り

  • #find_each
  • #find_in_batches

#find_each

レコードを分割して取得(デフォルト1000)し、1レコードづつ処理をする

User.find_each do |user|
  NewsMailer.weekly(user).deliver_now
end
SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1000
SELECT "users".* FROM "users" WHERE ("users"."id" > 1000) ORDER BY "users"."id" ASC LIMIT 1000
...

#where 等にチェインもできる

User.where(weekly_subscriber: true).find_each do |user|

オプション

  • :start : 処理開始位置
  • :batch_size : 1回の処理で実行するレコード数

#find_in_batches

レコードを分割して取得(デフォルト1000)し、配列に渡して処理をする

Invoice.find_in_batches do |invoices|
  export.add_invoices(invoices)
end

参考