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

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 fi where:

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 ce Model.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ă pluckconverteș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ă:

  1. interogarea eficientă a unui tabel de bază de date asociat pentru…
  2. generarea unui tablou din tabelul asociat cu toate cheile_străine ale obiectelor din tabelul primar
  3. 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.

.

Lasă un răspuns

Adresa ta de email nu va fi publicată.