Column Down
select
en pluck
zijn twee verschillende en nuttige manieren om de waarden van een of meer kolommen in een databasetabel als een verzameling terug te geven. Bijvoorbeeld, stel u heeft een questions
tabel in uw database. Elke question
zou drie velden kunnen hebben: id
, question_text
, en een foreign_key
uit een bijbehorende tabel. Om de waarden van alleen de kolom question_text
terug te geven, zou u select
of pluck
gebruiken. Ik wil graag de verschillen tussen deze twee methoden verkennen en eindigen met een toepassing van pluck
binnen een Rails applicatie.
Select
select
werkt op twee unieke manieren:
i.select
neemt een blok en werkt net als Array#select
.
Model.all.select { |m| m.field == value }
Dit bouwt een array van Ruby objecten uit de database voor het bereik, converteert ze in een array en itereert er doorheen met Array#select
.
select
vswhere
Het invoeren van een blok in
select
met een grote gegevensverzameling (d.w.z. veel rijen) is langzamer dan het gebruik van andere strategieën, zoalswhere
:
Model.where(field: value)
omdat met
Model.all.select { |m| m.field == value }
, Rails eerst alle tabelrijen zal omzetten in Ruby objecten, en dan het gegeven blok voor elk Ruby object zal uitvoeren, terwijlModel.where(field: value)
een SQL verklaring genereert die het zware werk aan SQL uit handen geeft, wat sneller is dan Ruby voor dit type filtering.
ii. select
wijzigt het SELECT
statement voor de SQL query zodat alleen bepaalde velden worden opgehaald:
Model.select(:field)
# =>
Voorbeeld, van een project van mij:
Question.select(:question_text)
# => #<ActiveRecord::Relation >
Dit genereert de volgende SQL:
SELECT "questions"."question_text" FROM "questions"
Merk op dat in dit tweede voorbeeld, de select
methode geen array retourneert; het retourneert een ActiveRecord::Relation object. Als gevolg daarvan kunt u er andere ActiveRecord::QueryMethods aan koppelen. Bijvoorbeeld:
Question.select(:question_text).limit(5)# => #<ActiveRecord::Relation >
Dit genereert de volgende SQL:
SELECT "questions"."question_text" FROM "questions" LIMIT ? ]
Pluk
Uit de Rails Guides:
pluck
kan worden gebruikt om query’s uit te voeren op enkele of meerdere kolommen uit de onderliggende tabel van een model. Het accepteert een lijst met kolomnamen als argument en retourneert een array met waarden van de opgegeven kolommen met het bijbehorende gegevenstype.
Het belangrijke punt hier is dat pluck
een array retourneert. Het retourneert geen ActiveRecord::Relation-object, zoals select
. Dus, bijvoorbeeld:
Question.pluck(:question_text)# => # this returns an array with all of the values from the question_text column from the questions table.
Omdat pluck
het resultaat van een database query omzet in een Ruby array zonder een ActiveRecord
object te construeren, is het performanter dan select
.
Dat pluck
een array retourneert, betekent echter dat je geen standaard ActiveRecord
queries kunt koppelen aan pluck
. Dit zal een NoMethodError
opleveren:
Question.pluck(:question_text).limit(5)# => NoMethodError: undefined method `limit' for #<Array:0x007fc5c1dfb3b0>
Maar pluck
werkt wel op ActiveRecord
objecten, dus het volgende zal het verwachte resultaat opleveren:
Question.limit(5).pluck(:question_text)#=>
pluck
kan meerdere argumenten aannemen om een multidimensionale array te construeren:
Question.pluck(:question_text, :course_id)#=> , , ...]
Wanneer zou ik Pluck gebruiken?
Ik heb pluck
gebruikt om ActiveRecord
modelobjecten te scopen om te bepalen welke modelobjecten geassocieerde records in een andere tabel hebben.
Neem bijvoorbeeld de volgende klasse:
class Appointment < ActiveRecord::Base
has_many :chargesend
Als we willen bepalen welke appointments
charges
hebben en welke niet, kunnen we pluck
in een scope
gebruiken. Hier is hoe:
Vooreerst, onthoud dat voor Model.where(field: value)
, value
ofwel een enkel object kan zijn (zoals integer
, string
, enz.), of het kan een array
van objecten zijn.
Dus, het volgende is geldig en zal alle appointments
met ids
teruggeven die in de array zijn opgenomen.
Appointment.where(id: )# => returns all appointments with ids that are included in the array
Wel, we weten dat pluck
een array retourneert, dus kunnen we een array construeren die de foreign keys bevat die we willen scopen in het bijbehorende model. Als we bijvoorbeeld willen bepalen welke appointments
charges
hebben geassocieerd, kunnen we een array maken van de appointment_id
kolom van de charges
tabel, zoals dit:
Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like:
Om te bepalen welke appointments
kosten hebben geassocieerd, kunnen we schrijven:
Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )
En dit omzetten in een scope op het Appointment
model:
class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }end
Wanneer we nu dus willen bepalen welke appointments
geassocieerde charges
hebben, kunnen we schrijven:
Appointment.received_payment_info#=> #<ActiveRecord::Relation
wat de volgende SQL queries genereert:
SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)
pluck
waarmee we:
- efficiënt een geassocieerde databasetabel te bevragen om…
- een array te genereren uit de geassocieerde tabel met alle foreign_keys van objecten uit de primaire tabel
- die array te gebruiken om te bepalen welke objecten in de primaire tabel geassocieerde objecten hebben in de secundaire tabel
Ik hoop dat je dit nuttig vond. Veel plezier met plukken en selecteren.