Column Down
select
și pluck
sunt două moduri diferite și utile de a returna valorile din una sau mai multe coloane dintr-o tabelă de bază de date sub forma unei colecții. De exemplu, imaginați-vă că aveți un tabel questions
în baza de date. Fiecare question
ar putea avea trei câmpuri: id
, question_text
și un foreign_key
dintr-un tabel asociat. Pentru a returna valorile doar din coloana question_text
, ați folosi select
sau pluck
. Aș dori să explorez diferențele dintre aceste două metode și să închei cu o aplicație a pluck
în cadrul unei aplicații Rails.
Select
select
funcționează în două moduri unice:
i.select
ia un bloc și funcționează la fel ca Array#select
.
Model.all.select { |m| m.field == value }
Aceasta construiește o matrice de obiecte Ruby din baza de date pentru domeniul de aplicare, convertindu-le într-o matrice și iterând prin ele folosind Array#select
.
select
vswhere
Pasarea unui bloc în
select
cu un set mare de date (de ex. multe rânduri) este mai lent decât utilizarea altor strategii, cum ar fiwhere
:
Model.where(field: value)
pentru că, cu
Model.all.select { |m| m.field == value }
, Rails va converti mai întâi toate rândurile din tabel în obiecte Ruby și apoi va rula blocul dat pentru fiecare obiect Ruby, în timp ceModel.where(field: value)
generează o instrucțiune SQL care descarcă munca grea către SQL, care este mai rapid decât Ruby pentru acest tip de filtrare.
ii. select
modifică instrucțiunea SELECT
pentru interogarea SQL astfel încât doar anumite câmpuri să fie recuperate:
Model.select(:field)
# =>
De exemplu, dintr-un proiect de-al meu:
Question.select(:question_text)
# => #<ActiveRecord::Relation >
Aceasta generează următorul SQL:
SELECT "questions"."question_text" FROM "questions"
Rețineți că în acest al doilea exemplu, metoda select
nu returnează o matrice; ea returnează un obiect ActiveRecord::Relation. Ca urmare, puteți să înlănțuiți alte metode ActiveRecord::QueryMethods la aceasta. De exemplu:
Question.select(:question_text).limit(5)# => #<ActiveRecord::Relation >
Aceasta generează următorul SQL:
SELECT "questions"."question_text" FROM "questions" LIMIT ? ]
Pluck
Din Ghidurile Rails:
pluck
poate fi utilizată pentru a interoga una sau mai multe coloane din tabelul de bază al unui model. Acceptă ca argument o listă de nume de coloane și returnează o matrice de valori ale coloanelor specificate cu tipul de date corespunzător.
Punctul important aici este că pluck
returnează o matrice. Nu returnează un obiect ActiveRecord::Relation, ca select
. Deci, de exemplu:
Question.pluck(:question_text)# => # this returns an array with all of the values from the question_text column from the questions table.
Pentru că pluck
convertește rezultatul unei interogări în baza de date într-un tablou Ruby fără a construi un obiect ActiveRecord
, este mai performant decât select
.
Cu toate acestea, faptul că pluck
returnează un tablou înseamnă că nu puteți înlănțui interogări standard ActiveRecord
pe pluck
. Făcând acest lucru va returna un NoMethodError
:
Question.pluck(:question_text).limit(5)# => NoMethodError: undefined method `limit' for #<Array:0x007fc5c1dfb3b0>
Dar pluck
funcționează pe obiecte ActiveRecord
, așa că următoarele vor returna rezultatul așteptat:
Question.limit(5).pluck(:question_text)#=>
pluck
poate primi mai multe argumente pentru a construi un tablou multidimensional:
Question.pluck(:question_text, :course_id)#=> , , ...]
Când aș putea folosi Pluck ?
Am folosit pluck
pentru a extinde ActiveRecord
obiecte de model pentru a determina ce obiecte de model au înregistrări asociate într-un alt tabel.
De exemplu, să luăm următoarea clasă:
class Appointment < ActiveRecord::Base
has_many :chargesend
Dacă vrem să determinăm care appointments
au charges
și care nu au, putem folosi pluck
într-un scope
. Iată cum:
În primul rând, amintiți-vă că pentru Model.where(field: value)
, value
poate fi fie un singur obiect (cum ar fi integer
, string
, etc.), fie poate fi un array
de obiecte.
Așa că, ceea ce urmează este valabil și va returna toate appointments
cu ids
care sunt incluse în matrice.
Appointment.where(id: )# => returns all appointments with ids that are included in the array
Ei bine, știm că pluck
returnează un array, deci putem construi un array care include cheile străine pe care dorim să le extindem în modelul asociat. De exemplu, dacă dorim să determinăm care appointments
au asociat charges
, putem crea un array din coloana appointment_id
a tabelului charges
, astfel:
Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like:
Pentru a determina care appointments
au taxe asociate, putem scrie:
Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like:
Pentru a determina care appointments
au taxe asociate, putem scrie:
Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )
Și convertind acest lucru într-un domeniu de aplicare pe modelul Appointment
:
class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }end
Acum, când vrem să determinăm ce appointments
au asociate charges
, putem scrie:
class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }end
:
Appointment.received_payment_info#=> #<ActiveRecord::Relation
ceea ce generează următoarele interogări SQL:
SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)
pluck
ne-a permis să:
- interogarea eficientă a unui tabel de bază de date asociat pentru…
- generarea unui tablou din tabelul asociat cu toate cheile_străine ale obiectelor din tabelul primar
- utilizarea acelui tablou pentru a determina ce obiecte din tabelul primar au obiecte asociate în tabelul secundar
Sper că v-a fost de ajutor. Bucurați-vă de culegere și selecție.
.