Column Down
select
et pluck
sont deux façons différentes et utiles de retourner les valeurs d’une ou plusieurs colonnes d’une table de base de données sous forme de collection. Par exemple, imaginez que vous avez une table questions
dans votre base de données. Chaque question
pourrait avoir trois champs : id
, question_text
, et un foreign_key
provenant d’une table associée. Pour retourner les valeurs de la seule colonne question_text
, vous utiliseriez select
ou pluck
. J’aimerais explorer les différences entre ces deux méthodes et terminer par une application de pluck
à l’intérieur d’une application Rails.
Select
select
fonctionne de deux façons uniques :
i.select
prend un bloc et fonctionne comme Array#select
.
Model.all.select { |m| m.field == value }
Ceci construit un tableau d’objets Ruby à partir de la base de données pour la portée, les convertissant en un tableau et les itérant à travers eux en utilisant Array#select
.
select
vswhere
Passer un bloc dans
select
avec un grand ensemble de données (i.e. de nombreuses lignes) est plus lent que l’utilisation d’autres stratégies, commewhere
:
Model.where(field: value)
parce qu’avec
Model.all.select { |m| m.field == value }
, Rails va d’abord convertir toutes les lignes de la table en objets Ruby, puis exécuter le bloc donné pour chaque objet Ruby, tandis queModel.where(field: value)
génère une instruction SQL qui décharge le gros du travail à SQL, qui est plus rapide que Ruby pour ce type de filtrage.
ii. select
modifie l’instruction SELECT
pour la requête SQL afin que seuls certains champs soient récupérés:
Model.select(:field)
# =>
Par exemple, à partir d’un de mes projets:
Question.select(:question_text)
# => #<ActiveRecord::Relation >
Cela génère le SQL suivant:
SELECT "questions"."question_text" FROM "questions"
Veuillez noter que dans ce deuxième exemple, la méthode select
ne renvoie pas un tableau ; elle renvoie un objet ActiveRecord::Relation. Par conséquent, vous pouvez y enchaîner d’autres ActiveRecord::QueryMethods. Par exemple :
Question.select(:question_text).limit(5)# => #<ActiveRecord::Relation >
Cela génère le SQL suivant :
SELECT "questions"."question_text" FROM "questions" LIMIT ? ]
Pluck
Dans les guides Rails :
pluck
peut être utilisée pour interroger une ou plusieurs colonnes de la table sous-jacente d’un modèle. Elle accepte une liste de noms de colonnes comme argument et renvoie un tableau de valeurs des colonnes spécifiées avec le type de données correspondant.
Le point important ici est que pluck
renvoie un tableau. Il ne renvoie pas un objet ActiveRecord::Relation, comme select
. Ainsi, par exemple :
Question.pluck(:question_text)# => # this returns an array with all of the values from the question_text column from the questions table.
Parce que pluck
convertit un résultat de requête de base de données en un tableau Ruby sans construire un objet ActiveRecord
, il est plus performant que select
.
Cependant, le fait que pluck
renvoie un tableau signifie que vous ne pouvez pas enchaîner des requêtes standard ActiveRecord
sur pluck
. Le faire retournera un NoMethodError
:
Question.pluck(:question_text).limit(5)# => NoMethodError: undefined method `limit' for #<Array:0x007fc5c1dfb3b0>
Mais pluck
fonctionne sur les objets ActiveRecord
, donc ce qui suit retournera le résultat attendu:
Question.limit(5).pluck(:question_text)#=>
pluck
peut prendre plusieurs arguments pour construire un tableau multidimensionnel:
Question.pluck(:question_text, :course_id)#=> , , ...]
Quand utiliserais-je Pluck ?
J’ai utilisé pluck
pour scopeer des objets de modèle ActiveRecord
afin de déterminer quels objets de modèle ont des enregistrements associés dans une autre table.
Par exemple, prenez la classe suivante:
class Appointment < ActiveRecord::Base
has_many :chargesend
Si nous voulons déterminer quels appointments
ont charges
et lesquels n’en ont pas, nous pouvons utiliser pluck
dans un scope
. Voici comment :
D’abord, rappelez-vous que pour Model.where(field: value)
, value
peut être soit un objet unique (comme integer
, string
, etc.), soit un array
d’objets.
Donc, ce qui suit est valide et retournera tous les appointments
avec ids
qui sont inclus dans le tableau.
Appointment.where(id: )# => returns all appointments with ids that are included in the array
Bien, nous savons que pluck
renvoie un tableau, donc nous pouvons construire un tableau qui inclut les clés étrangères que nous voulons scope dans le modèle associé. Par exemple, si nous voulons déterminer quels appointments
ont des charges
associés, nous pouvons créer un tableau à partir de la colonne appointment_id
de la table charges
, comme ceci:
Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like:
Pour déterminer quels appointments
ont des charges associées, nous pouvons écrire :
Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )
Et en convertissant cela en une portée sur le modèle Appointment
:
class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }end
Alors maintenant quand nous voulons déterminer quels appointments
ont des charges
associés, nous pouvons écrire :
Appointment.received_payment_info#=> #<ActiveRecord::Relation
ce qui génère les requêtes SQL suivantes:
SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)
pluck
nous a permis de :
- interroger efficacement une table de base de données associée pour…
- générer un tableau à partir de la table associée avec toutes les clés étrangères des objets de la table primaire
- utiliser ce tableau pour déterminer quels objets de la table primaire ont des objets associés dans la table secondaire
J’espère que vous avez trouvé cela utile. Amusez-vous bien à plumer et à sélectionner.