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 vs where

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, som where:

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, mens Model.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:

  1. effektivt forespørge en tilknyttet databasetabel for at…
  2. generere et array fra den tilknyttede tabel med alle foreign_keys for objekter fra den primære tabel
  3. 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.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.