select y pluck son dos formas diferentes y útiles de devolver los valores de una o más columnas de una tabla de la base de datos como una colección. Por ejemplo, imagine que tiene una tabla questions en su base de datos. Cada question podría tener tres campos: id, question_text y un foreign_key de una tabla asociada. Para devolver los valores de sólo la columna question_text, utilizaría select o pluck. Me gustaría explorar las diferencias entre estos dos métodos y terminar con una aplicación de pluck dentro de una aplicación Rails.

Select

select funciona de dos maneras únicas:

i.select toma un bloque y funciona igual que Array#select.

Model.all.select { |m| m.field == value }

Esto construye un array de objetos Ruby desde la base de datos para el ámbito, convirtiéndolos en un array e iterando a través de ellos usando Array#select.

select vs where

Pasar un bloque a select con un conjunto de datos grande (es decir muchas filas) es más lento que utilizar otras estrategias, como where:

Model.where(field: value)

porque con Model.all.select { |m| m.field == value }, Rails convertirá primero todas las filas de la tabla en objetos Ruby, y luego ejecutará el bloque dado para cada objeto Ruby, mientras que Model.where(field: value) genera una sentencia SQL que descarga el trabajo pesado a SQL, que es más rápido que Ruby para este tipo de filtrado.

ii. select modifica la sentencia SELECT de la consulta SQL para que sólo se recuperen ciertos campos:

Model.select(:field)
# =>

Por ejemplo, de un proyecto mío:

Question.select(:question_text)
# => #<ActiveRecord::Relation >

Esto genera el siguiente SQL:

SELECT "questions"."question_text" FROM "questions"

Tenga en cuenta que en este segundo ejemplo, el método select no devuelve un array; devuelve un objeto ActiveRecord::Relation. Como resultado, puedes encadenar otros ActiveRecord::QueryMethods a él. Por ejemplo:

Question.select(:question_text).limit(5)# => #<ActiveRecord::Relation >

Esto genera el siguiente SQL:

SELECT "questions"."question_text" FROM "questions" LIMIT ? ]

Pluck

De las guías de Rails:

pluckpuede utilizarse para consultar una o varias columnas de la tabla subyacente de un modelo. Acepta una lista de nombres de columnas como argumento y devuelve un array de valores de las columnas especificadas con el tipo de datos correspondiente.

El punto importante aquí es que pluck devuelve un array. No devuelve un objeto ActiveRecord::Relation, como select. Así, por ejemplo:

Question.pluck(:question_text)# => # this returns an array with all of the values from the question_text column from the questions table.

Debido a que pluck convierte el resultado de una consulta a la base de datos en una matriz de Ruby sin construir un objeto ActiveRecord, es más eficaz que select.

Sin embargo, el hecho de que pluck devuelva una matriz significa que no se pueden encadenar consultas estándar ActiveRecord en pluck. Hacerlo devolverá un NoMethodError:

Question.pluck(:question_text).limit(5)# => NoMethodError: undefined method `limit' for #<Array:0x007fc5c1dfb3b0>

Pero pluck sí funciona con objetos ActiveRecord, así que lo siguiente devolverá el resultado esperado:

Question.limit(5).pluck(:question_text)#=> 

pluckpuede tomar múltiples argumentos para construir una matriz multidimensional:

Question.pluck(:question_text, :course_id)#=> , , ...]

¿Cuándo utilizaría Pluck?

He utilizado pluck para el alcance de ActiveRecord objetos del modelo para determinar qué objetos del modelo tienen registros asociados en otra tabla.

Por ejemplo, tome la siguiente clase:

class Appointment < ActiveRecord::Base
has_many :chargesend

Si queremos determinar qué appointments tienen charges y cuáles no, podemos utilizar pluck en un scope. He aquí cómo:

Primero, recuerda que para Model.where(field: value), value puede ser un solo objeto (como integer, string, etc.), o puede ser un array de objetos.

Así, lo siguiente es válido y devolverá todos los appointments con ids que estén incluidos en el array.

Appointment.where(id: )# => returns all appointments with ids that are included in the array

Bueno, sabemos que pluck devuelve un array, por lo que podemos construir un array que incluya las claves foráneas que queremos abarcar en el modelo asociado. Por ejemplo, si queremos determinar qué appointments tienen asociado charges, podemos crear un array a partir de la columna appointment_id de la tabla charges, así:

Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like: 

Para determinar qué appointments tienen cargos asociados, podemos escribir:

Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )

Y convirtiendo esto en un ámbito en el modelo Appointment:

class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }end

Así que ahora cuando queramos determinar qué appointments tienen asociados charges, podemos escribir:

Appointment.received_payment_info#=> #<ActiveRecord::Relation 

lo que genera las siguientes consultas SQL:

SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)

pluck nos permite:

  1. consultar de forma eficiente una tabla de la base de datos asociada para…
  2. generar un array de la tabla asociada con todas las foreign_keys de los objetos de la tabla primaria
  3. utilizar ese array para determinar qué objetos de la tabla primaria tienen objetos asociados en la tabla secundaria

Espero que os haya resultado útil. Disfruta desplumando y seleccionando.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.