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

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, comme where:

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 que Model.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 :

  1. interroger efficacement une table de base de données associée pour…
  2. générer un tableau à partir de la table associée avec toutes les clés étrangères des objets de la table primaire
  3. 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.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.