pluckメソッドについて
pluckとは?
1つのモデルで使用されているテーブルからカラム (1つでも複数でも可) を取得するクエリを送信するのに使用できます。引数としてカラム名のリストを与えると、指定したカラムの値の配列を、対応するデータ型で返します。(Railsガイドより)
基本形は
モデル名.pluck(:カラム名)
戻り値について
引数なしの場合
SQL SELECT "users".*
から全てのデータを取得していることが分かります。
値は2次元配列(配列の中に配列)
として返します。
User.pluck SELECT "users".* FROM "users" # <= usersテーブルから全てのデータを取得する => [ [1, "田中", "健二"], [2, "松尾, "浩"], [3, "池田", "涼"] ]
引数が一つの場合
引数で指定したカラムのみ
を取得します。また、値は配列として返します。
User.pluck(:last_name) SELECT "users"."last_name" FROM "users" #<= usersテーブルからlast_nameカラムのみ取得している => ["田中", "松尾", "池田"]
引数が複数の場合
値は2次元配列として返します。
User.pluck(:last_name, :first_name) SELECT "users"."last_name", "users"."first_name" FROM "users" => [["田中", "健二"], ["松尾", "浩"], ["池田", "涼"]]
pluckの後に他のクエリメソッドをチェーンできない!!
pluckの戻り値は配列なので、その後にクエリメソッドをチェーンすることはできません。
User.pluck(:last_name).limit(1) (0.2ms) SELECT "users"."last_name" FROM "users" # NoMethodError: undefined method `limit' for #<Array:0x00007f8def865770> # pluckの前に配置することでエラーを回避できます。 User.limit(1).pluck(:last_name) (0.2ms) SELECT "users"."last_name" FROM "users" LIMIT ? [["LIMIT", 1]] => ["田中"]
mapメソッドとの違い
先程のpluckを使用してlast_name
カラムを取得する場合は以下のようになります。
User.pluck(:last_name) SELECT "users"."last_name" FROM "users" => ["田中", "松尾", "池田"]
これと等価の値をmapを使用して取得する場合には以下のようになります。
User.all.map(&:last_name) SELECT "users".* FROM "users" => ["田中", "松尾", "池田"]
2つの違いはSQL文を見ると分かります。
pluckはSELECT "users"."last_name"
とあるようにDBから取得する際にデータを絞り込んでいるのが分かります。
それに対して、mapはSELECT "users".* FROM "users"
とあるようにDBから全てのデータを取得してから絞り込んでいるのが分かります。
このことから特定のカラムのみを扱いたい場合はpluck
を使用する方がメモリの消費を抑えることができます!!
mapを使用した方がいい場合
インスタンス化されたオブジェクト
に対して実行する場合はmap
の方がパフォーマンスはいいです。
以下のようにループ文の中でそれぞれを実行した場合
users = User.all Benchmark.bm 10 do |r| r.report "pluck" do 2000.times { users.pluck(:id) } end r.report "map" do 2000.times { users.map(&:id) } end end
user system total real pluck 0.148876 0.000580 0.149456 ( 0.149820) map 0.059511 0.000156 0.059667 ( 0.059783)