select e pluck são duas formas diferentes e úteis de retornar os valores de uma ou mais colunas em uma tabela de banco de dados como uma coleção. Por exemplo, imagine que você tem uma tabela questions em seu banco de dados. Cada question pode ter três campos: id, question_text, e um foreign_key de uma tabela associada. Para retornar os valores apenas da coluna question_text, você usaria select ou pluck. Eu gostaria de explorar as diferenças entre estes dois métodos e terminar com uma aplicação de pluck dentro de uma aplicação Rails.

Select

select funciona de duas maneiras únicas:

i.select pega um bloco e funciona exatamente como Array#select.

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

Constrói um array de objetos Ruby do banco de dados para o escopo, convertendo-os em um array e iterando através deles usando Array#select.

select vs where

Passar um bloco em select com um grande conjunto de dados (i.e. muitas linhas) é mais lento do que usar outras estratégias, como where:

Model.where(field: value)

porque com Model.all.select { |m| m.field == value }, Rails primeiro converte todas as linhas da tabela em objetos Ruby, e depois executa o bloco dado para cada objeto Ruby, enquanto Model.where(field: value) gera uma instrução SQL que descarrega o levantamento pesado para SQL, que é mais rápido do que Ruby para este tipo de filtragem.

ii. select modifica a instrução SELECT para a consulta SQL para que somente certos campos sejam recuperados:

Model.select(:field)
# =>

Por exemplo, de um projeto meu:

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

Gera o seguinte SQL:

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

Por favor note que neste segundo exemplo, o método select não retorna um array; ele retorna um objeto ActiveRecord::Relation. Como resultado, você pode encadear outros ActiveRecord::QueryMethods a ele. Por exemplo:

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

Gera o seguinte SQL:

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

Pluck

From the Rails Guides:

pluck pode ser usado para consultar colunas simples ou múltiplas da tabela subjacente de um modelo. Ele aceita uma lista de nomes de colunas como argumento e retorna um array de valores das colunas especificadas com o tipo de dado correspondente.

O ponto importante aqui é que pluck retorna um array. Ele não retorna um objeto ActiveRecord::Relation, como select. Então, por exemplo:

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

Porque pluck converte um resultado de consulta de base de dados num array Ruby sem construir um objecto ActiveRecord é mais performante que select.

No entanto, que pluck retorna um array significa que não pode fazer consultas em cadeia padrão ActiveRecord em pluck. Fazendo isso irá retornar um NoMethodError:

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

mas pluck trabalha em ActiveRecord objetos, então o seguinte irá retornar o resultado esperado:

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

pluck pode levar múltiplos argumentos para construir um array multidimensional:

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

Quando eu usaria Pluck ?

Usei pluck para escopo ActiveRecord objetos de modelo para determinar quais objetos de modelo têm registros associados em outra tabela.

Por exemplo, pegue a seguinte classe:

class Appointment < ActiveRecord::Base
has_many :chargesend

Se quisermos determinar quais appointments têm charges e quais não têm, podemos usar pluck em um scope. Eis como:

Primeiro, lembre-se que para Model.where(field: value), value pode ser um único objeto (como integer, string, etc.), ou pode ser um array de objetos.

Então, o seguinte é válido e retornará todos os appointments com ids que estão incluídos no array.

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

Bem, sabemos que pluck retorna um array, assim podemos construir um array que inclui as chaves estrangeiras que queremos escanear no modelo associado. Por exemplo, se quisermos determinar quais appointments têm associado charges, podemos criar um array a partir da coluna appointment_id da tabela charges, assim:

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

Para determinar quais appointments têm associados encargos, podemos escrever:

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

E convertendo isto em um escopo no modelo Appointment:

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

Então agora quando queremos determinar quais appointments têm associados charges, podemos escrever:

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

que gera as seguintes 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 que nos permitem:

  1. consultar eficientemente uma tabela de banco de dados associada a…
  2. gerar um array da tabela associada com todas as chaves_estrangeiras de objetos da tabela primária
  3. usar esse array para determinar quais objetos da tabela primária têm objetos associados na tabela secundária

Espero que você tenha achado isso útil. Aproveite a depuração e selecione.

Deixe uma resposta

O seu endereço de email não será publicado.