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

Passare un blocco in select con un grande insieme di dati (cioè molte righe) è più lento che usare altre strategie, come where:

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

  1. interrogare in modo efficiente una tabella di database associata per…
  2. generare un array dalla tabella associata con tutte le foreign_keys degli oggetti della tabella primaria
  3. 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.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.