Column Down
select
og pluck
er to forskellige og nyttige måder at returnere værdierne fra en eller flere kolonner i en databasetabel som en samling på. Forestil dig f.eks., at du har en questions
tabel i din database. Hver question
kan have tre felter: id
, question_text
og et foreign_key
fra en tilknyttet tabel. Hvis du kun vil returnere værdierne fra kolonnen question_text
, skal du bruge select
eller pluck
for at returnere værdierne fra kolonnen question_text
. Jeg vil gerne undersøge forskellene mellem disse to metoder og slutte af med en anvendelse af pluck
inde i et Rails-program.
Select
select
fungerer på to unikke måder:
i.select
tager en blok og fungerer ligesom Array#select
.
Model.all.select { |m| m.field == value }
Dette opbygger et array af Ruby-objekter fra databasen for anvendelsesområdet, konverterer dem til et array og iterererer gennem dem ved hjælp af Array#select
.
select
vswhere
Det er muligt at sende en blok ind i
select
med et stort datasæt (dvs. mange rækker) er langsommere end at bruge andre strategier, somwhere
:
Model.where(field: value)
fordi med
Model.all.select { |m| m.field == value }
vil Rails først konvertere alle tabelrækkerne til Ruby-objekter og derefter køre den givne blok for hvert Ruby-objekt, mensModel.where(field: value)
genererer en SQL-anvisning, der aflæsser det tunge arbejde til SQL, som er hurtigere end Ruby til denne type filtrering.
ii. select
ændrer SELECT
-erklæringen for SQL-forespørgslen, så kun visse felter hentes:
Model.select(:field)
# =>
For eksempel fra et af mine projekter:
Question.select(:question_text)
# => #<ActiveRecord::Relation >
Dette genererer følgende SQL:
SELECT "questions"."question_text" FROM "questions"
Bemærk venligst, at i dette andet eksempel returnerer select
-metoden ikke et array; den returnerer et ActiveRecord::Relation-objekt. Som følge heraf kan du kæde andre ActiveRecord::QueryMethods til den. For eksempel:
Question.select(:question_text).limit(5)# => #<ActiveRecord::Relation >
Dette genererer følgende SQL:
SELECT "questions"."question_text" FROM "questions" LIMIT ? ]
Pluk
Fra Rails-vejledningerne:
pluck
kan bruges til at forespørge på enkelte eller flere kolonner fra den underliggende tabel i en model. Den accepterer en liste over kolonnenavne som argument og returnerer et array af værdier for de angivne kolonner med den tilsvarende datatype.
Det vigtige punkt her er, at pluck
returnerer et array. Den returnerer ikke et ActiveRecord::Relation-objekt, som select
. Så for eksempel:
Question.pluck(:question_text)# => # this returns an array with all of the values from the question_text column from the questions table.
Da pluck
konverterer et databaseforespørgselsresultat til et Ruby-array uden at konstruere et ActiveRecord
-objekt, er det mere performant end select
.
Den omstændighed, at pluck
returnerer et array, betyder imidlertid, at du ikke kan kæde standard ActiveRecord
-forespørgsler på pluck
. Hvis du gør det, vil du returnere en NoMethodError
:
Question.pluck(:question_text).limit(5)# => NoMethodError: undefined method `limit' for #<Array:0x007fc5c1dfb3b0>
Men pluck
virker på ActiveRecord
-objekter, så følgende vil returnere det forventede resultat:
Question.limit(5).pluck(:question_text)#=>
pluck
kan tage flere argumenter for at konstruere et flerdimensionalt array:
Question.pluck(:question_text, :course_id)#=> , , ...]
Hvornår vil jeg bruge Pluck ?
Jeg har brugt pluck
til at afgrænse ActiveRecord
modelobjekter for at bestemme, hvilke modelobjekter der har tilknyttede poster i en anden tabel.
Tag f.eks. følgende klasse:
class Appointment < ActiveRecord::Base
has_many :chargesend
Hvis vi vil bestemme, hvilke appointments
der har charges
, og hvilke der ikke har det, kan vi bruge pluck
i en scope
. Sådan gør vi:
Først skal du huske, at for Model.where(field: value)
kan value
enten være et enkelt objekt (som integer
, string
osv.), eller det kan være et array
af objekter.
Så følgende er gyldigt og returnerer alle appointments
med ids
, der er inkluderet i arrayet.
Appointment.where(id: )# => returns all appointments with ids that are included in the array
Vi ved, at pluck
returnerer et array, så vi kan konstruere et array, der indeholder de fremmednøgler, som vi ønsker at have scope på i den tilknyttede model. Hvis vi f.eks. vil bestemme, hvilke appointments
der har tilknyttet charges
, kan vi oprette et array fra appointment_id
-kolonnen i charges
-tabellen som her:
Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like:
For at bestemme, hvilke appointments
der har tilknyttede gebyrer, kan vi skrive:
Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like:
For at bestemme, hvilke appointments
der har tilknyttede gebyrer, kan vi skrive:
Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )
Og ved at konvertere dette til et omfang på Appointment
-modellen:
class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }end
Så når vi nu vil bestemme, hvilke appointments
der har tilknyttede charges
, kan vi skrive:
class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }end
Så når vi nu vil bestemme, hvilke appointments
der har tilknyttede charges
, kan vi skrive:
Appointment.received_payment_info#=> #<ActiveRecord::Relation
som genererer følgende SQL-forespørgsler:
SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)
pluck
gav os mulighed for at:
- effektivt forespørge en tilknyttet databasetabel for at…
- generere et array fra den tilknyttede tabel med alle foreign_keys for objekter fra den primære tabel
- anvende dette array til at bestemme, hvilke objekter i den primære tabel der har tilknyttede objekter i den sekundære tabel
Jeg håber, at du fandt dette nyttigt. God fornøjelse med at plukke og udvælge.