Column Down
select
e pluck
sono due modi diversi e utili per restituire i valori di una o più colonne in una tabella di database come collezione. Per esempio, immaginate di avere una tabella questions
nel vostro database. Ogni question
potrebbe avere tre campi: id
, question_text
, e un foreign_key
da una tabella associata. Per restituire i valori della sola colonna question_text
, usereste select
o pluck
. Vorrei esplorare le differenze tra questi due metodi e finire con un’applicazione di pluck
all’interno di un’applicazione Rails.
Select
select
funziona in due modi unici:
i.select
prende un blocco e funziona proprio come Array#select
.
Model.all.select { |m| m.field == value }
Costruisce un array di oggetti Ruby dal database per lo scopo, convertendoli in un array e iterando attraverso di essi usando Array#select
.
select
vswhere
Passare un blocco in
select
con un grande insieme di dati (cioè molte righe) è più lento che usare altre strategie, comewhere
:
Model.where(field: value)
perché con
Model.all.select { |m| m.field == value }
, Rails prima converte tutte le righe della tabella in oggetti Ruby, e poi esegue il blocco dato per ogni oggetto Ruby, mentreModel.where(field: value)
genera uno statement SQL che scarica il lavoro pesante su SQL, che è più veloce di Ruby per questo tipo di filtraggio.
ii. select
modifica la dichiarazione SELECT
per la query SQL in modo da recuperare solo certi campi:
Model.select(:field)
# =>
Per esempio, da un mio progetto:
Question.select(:question_text)
# => #<ActiveRecord::Relation >
Questo genera il seguente SQL:
SELECT "questions"."question_text" FROM "questions"
Si noti che in questo secondo esempio, il metodo select
non restituisce un array; restituisce un oggetto ActiveRecord::Relation. Di conseguenza, potete concatenare altri ActiveRecord::QueryMethods ad esso. Per esempio:
Question.select(:question_text).limit(5)# => #<ActiveRecord::Relation >
Questo genera il seguente SQL:
SELECT "questions"."question_text" FROM "questions" LIMIT ? ]
Pluck
Dalle guide Rails:
pluck
può essere usato per interrogare colonne singole o multiple dalla tabella sottostante di un modello. Accetta una lista di nomi di colonne come argomento e restituisce un array di valori delle colonne specificate con il tipo di dati corrispondente.
Il punto importante qui è che pluck
restituisce un array. Non restituisce un oggetto ActiveRecord::Relation, come select
. Quindi, per esempio:
Question.pluck(:question_text)# => # this returns an array with all of the values from the question_text column from the questions table.
Perché pluck
converte il risultato di una query di database in un array Ruby senza costruire un oggetto ActiveRecord
, è più performante di select
.
Tuttavia, il fatto che pluck
restituisca un array significa che non puoi concatenare query standard ActiveRecord
su pluck
. Farlo restituirà un NoMethodError
:
Question.pluck(:question_text).limit(5)# => NoMethodError: undefined method `limit' for #<Array:0x007fc5c1dfb3b0>
Ma pluck
funziona su oggetti ActiveRecord
, quindi il seguente restituirà il risultato atteso:
Question.limit(5).pluck(:question_text)#=>
pluck
può prendere più argomenti per costruire un array multidimensionale:
Question.pluck(:question_text, :course_id)#=> , , ...]
Quando dovrei usare Pluck?
Ho usato pluck
per fare scope su ActiveRecord
oggetti modello per determinare quali oggetti modello hanno record associati in un’altra tabella.
Per esempio, prendiamo la seguente classe:
class Appointment < ActiveRecord::Base
has_many :chargesend
Se vogliamo determinare quali appointments
hanno charges
e quali no, possiamo usare pluck
in un scope
. Ecco come:
Prima di tutto, ricordate che per Model.where(field: value)
, value
può essere un singolo oggetto (come integer
, string
, ecc.), o può essere un array
di oggetti.
Quindi, il seguente è valido e restituirà tutti i appointments
con ids
che sono inclusi nell’array.
Appointment.where(id: )# => returns all appointments with ids that are included in the array
Bene, sappiamo che pluck
restituisce un array, quindi possiamo costruire un array che includa le chiavi esterne che vogliamo includere nel modello associato. Per esempio, se vogliamo determinare quali appointments
hanno associato charges
, possiamo creare un array dalla colonna appointment_id
della tabella charges
, come questo:
Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like:
Per determinare quali appointments
hanno associato degli oneri, possiamo scrivere:
Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )
E convertendo questo in un ambito sul modello Appointment
:
class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }end
Così ora quando vogliamo determinare quali appointments
hanno associato charges
, possiamo scrivere:
Appointment.received_payment_info#=> #<ActiveRecord::Relation
che genera le seguenti query SQL:
SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)
pluck
ci ha permesso di:
- interrogare in modo efficiente una tabella di database associata per…
- generare un array dalla tabella associata con tutte le foreign_keys degli oggetti della tabella primaria
- usare quell’array per determinare quali oggetti nella tabella primaria hanno oggetti associati nella tabella secondaria
Spero che sia stato utile. Divertiti a spennare e selezionare.