Column Down
select
と pluck
は、データベース テーブル内の 1 つまたは複数の列から値をコレクションとして返す、2 つの異なる便利な方法です。 たとえば、データベースに questions
テーブルがあるとします。 各question
は3つのフィールドを持っているかもしれません。 id
, question_text
, そして関連するテーブルの foreign_key
です。 question_text
列のみから値を返すには、select
または pluck
を使用します。 この2つのメソッドの違いを調べ、最後にRailsアプリケーション内でのpluck
のアプリケーションを紹介します。
Select
select
は2つの独自の方法で動作します:
i.select
はブロックを受け取り、Array#select
と同様に動作します。
Model.all.select { |m| m.field == value }
これはスコープに対してデータベースから Ruby オブジェクトの配列を構築し、配列に変換して Array#select
を使用してそれらを反復処理します。
select
vswhere
大きなデータセット (例) で
select
にブロックを渡すとwhere
:
Model.where(field: value)
なぜなら、
Model.all.select { |m| m.field == value }
では、Railsはまずテーブルの行をすべてRubyオブジェクトに変換し、各Rubyオブジェクトに対して与えられたブロックを実行しますが、Model.where(field: value)
はSQL文を生成して重い作業をSQLにオフロードし、この種のフィルタリングではRubyより速いからです。Model.select(:field)
# =>例えば、私のプロジェクトでは、
Question.select(:question_text)
# => #<ActiveRecord::Relation >これにより、次の SQL が生成されます:
SELECT "questions"."question_text" FROM "questions"この 2 番目の例では、
select
メソッドは配列を返さないことに注意してください;それは ActiveRecord::Relation オブジェクトを返します。 その結果、他のActiveRecord::QueryMethodsをこれに連結することができます。 例えば、Question.select(:question_text).limit(5)# => #<ActiveRecord::Relation >これは次のSQLを生成します。
SELECT "questions"."question_text" FROM "questions" LIMIT ? ]Pluck
Railsガイドより:
pluck
はモデルの基本テーブルから単一または複数の列を照会するために使用することができます。 引数として列名のリストを受け取り、対応するデータ型を持つ指定された列の値の配列を返します。ここで重要な点は、
pluck
は配列を返すということです。select
のようにActiveRecord::Relationオブジェクトを返すわけではありません。 たとえば、Question.pluck(:question_text)# => # this returns an array with all of the values from the question_text column from the questions table.
pluck
はActiveRecord
オブジェクトを作成せずにデータベースへの問い合わせ結果を Ruby の配列に変換するので、select
よりもパフォーマンスが高くなります。Question.pluck(:question_text).limit(5)# => NoMethodError: undefined method `limit' for #<Array:0x007fc5c1dfb3b0>しかし、
pluck
はActiveRecord
オブジェクトに対して動作するので、次のようにすると期待通りの結果を返します:Question.limit(5).pluck(:question_text)#=>
pluck
は多次元配列を構築するために複数の引数を取ることができます:Question.pluck(:question_text, :course_id)#=> , , ...]Pluck はいつ使うのか?
pluck
を使ってActiveRecord
モデル オブジェクトをスコープし、どのモデル オブジェクトが別のテーブルの関連レコードを持っているかを判断することができます。 以下はその方法です。まず、
Model.where(field: value)
の場合、value
は単一のオブジェクト(integer
やstring
など)か、オブジェクトのarray
であることを覚えておいてください。したがって、以下は有効で、配列に含まれる
ids
を持つすべてのを返すことになります。Appointment.where(id: )# => returns all appointments with ids that are included in the arrayさて、
pluck
が配列を返すことは分かっているので、関連付けられたモデルでスコープしたい外部キーを含む配列を構築することができます。 例えば、どのappointments
がcharges
と関連しているかを判断したい場合、以下のようにcharges
テーブルのappointment_id
カラムから配列を作成できます:Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like:どの
appointments
が料金と関連しているかを判断するには、以下のように記述できます。Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )これを
Appointment
モデルのスコープに変換すると:class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }endつまり、
appointments
がcharges
と関連付けられているかを判断したい場合は、次のように記述します。Appointment.received_payment_info#=> #<ActiveRecord::Relationと書くことができ、次のようなSQLクエリが生成されます:
SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)
pluck
によって、私たちは
- 関連データベース テーブルに効率的にクエリを実行して…
- 主テーブルからのオブジェクトのすべての foreign_key を含む関連テーブルから配列を生成し、
- その配列を使って主テーブルのオブジェクトと副テーブルの関連オブジェクトを判断する
これが役に立ったことを願っております。 摘出と選択を楽しんでください。