Column Down
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
vswhere
Passar um bloco em
select
com um grande conjunto de dados (i.e. muitas linhas) é mais lento do que usar outras estratégias, comowhere
:
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, enquantoModel.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:
- consultar eficientemente uma tabela de banco de dados associada a…
- gerar um array da tabela associada com todas as chaves_estrangeiras de objetos da tabela primária
- 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.