Column Down
select
und pluck
sind zwei verschiedene und nützliche Möglichkeiten, die Werte einer oder mehrerer Spalten in einer Datenbanktabelle als Sammlung zurückzugeben. Stellen Sie sich zum Beispiel vor, Sie haben eine questions
-Tabelle in Ihrer Datenbank. Jedes question
könnte drei Felder haben: id
, question_text
und ein foreign_key
aus einer zugehörigen Tabelle. Um nur die Werte aus der Spalte question_text
zurückzugeben, würden Sie select
oder pluck
verwenden. Ich möchte die Unterschiede zwischen diesen beiden Methoden untersuchen und mit einer Anwendung von pluck
innerhalb einer Rails-Anwendung enden.
Select
select
funktioniert auf zwei verschiedene Arten:
i.select
nimmt einen Block und funktioniert genau wie Array#select
.
Model.all.select { |m| m.field == value }
Dies baut ein Array von Ruby-Objekten aus der Datenbank für den Bereich auf, konvertiert sie in ein Array und iteriert mit Array#select
durch sie.
select
vswhere
Die Übergabe eines Blocks an
select
mit einem großen Datensatz (d.h.where
:
Model.where(field: value)
Denn mit
Model.all.select { |m| m.field == value }
konvertiert Rails zuerst alle Tabellenzeilen in Ruby-Objekte und führt dann den gegebenen Block für jedes Ruby-Objekt aus, währendModel.where(field: value)
eine SQL-Anweisung generiert, die die schwere Arbeit auf SQL verlagert, was bei dieser Art von Filterung schneller ist als Ruby.
ii. select
ändert die SELECT
-Anweisung für die SQL-Abfrage so, dass nur bestimmte Felder abgerufen werden:
Model.select(:field)
# =>
Zum Beispiel aus einem Projekt von mir:
Question.select(:question_text)
# => #<ActiveRecord::Relation >
Dies erzeugt die folgende SQL-Anweisung:
SELECT "questions"."question_text" FROM "questions"
Bitte beachten Sie, dass in diesem zweiten Beispiel die select
-Methode kein Array zurückgibt, sondern ein ActiveRecord::Relation-Objekt. Folglich können Sie andere ActiveRecord::QueryMethods mit ihr verketten. Zum Beispiel:
Question.select(:question_text).limit(5)# => #<ActiveRecord::Relation >
Dies erzeugt die folgende SQL:
SELECT "questions"."question_text" FROM "questions" LIMIT ? ]
Pluck
Aus den Rails Guides:
pluck
kann verwendet werden, um einzelne oder mehrere Spalten aus der zugrunde liegenden Tabelle eines Modells abzufragen. Es akzeptiert eine Liste von Spaltennamen als Argument und gibt ein Array von Werten der angegebenen Spalten mit dem entsprechenden Datentyp zurück.
Der wichtige Punkt hier ist, dass pluck
ein Array zurückgibt. Es gibt kein ActiveRecord::Relation Objekt zurück, wie select
. Zum Beispiel:
Question.pluck(:question_text)# => # this returns an array with all of the values from the question_text column from the questions table.
Da pluck
das Ergebnis einer Datenbankabfrage in ein Ruby-Array umwandelt, ohne ein ActiveRecord
-Objekt zu erzeugen, ist es leistungsfähiger als select
.
Dass pluck
jedoch ein Array zurückgibt, bedeutet, dass Sie keine Standard-ActiveRecord
-Abfragen mit pluck
verketten können. Wenn Sie dies tun, erhalten Sie ein NoMethodError
:
Question.pluck(:question_text).limit(5)# => NoMethodError: undefined method `limit' for #<Array:0x007fc5c1dfb3b0>
Aber pluck
funktioniert mit ActiveRecord
-Objekten, so dass die folgende Abfrage das erwartete Ergebnis liefert:
Question.limit(5).pluck(:question_text)#=>
pluck
kann mehrere Argumente annehmen, um ein mehrdimensionales Array zu erstellen:
Question.pluck(:question_text, :course_id)#=> , , ...]
Wann sollte ich Pluck verwenden?
Ich habe pluck
verwendet, um ActiveRecord
Modellobjekte zu erfassen, um festzustellen, welche Modellobjekte mit Datensätzen in einer anderen Tabelle verknüpft sind:
Nehmen wir zum Beispiel die folgende Klasse:
class Appointment < ActiveRecord::Base
has_many :chargesend
Wenn wir feststellen wollen, welche appointments
charges
haben und welche nicht, können wir pluck
in einer scope
verwenden. So geht’s:
Erinnern Sie sich zunächst daran, dass value
bei Model.where(field: value)
entweder ein einzelnes Objekt sein kann (wie integer
, string
usw.) oder ein array
von Objekten.
Das Folgende ist also gültig und gibt alle appointments
mit ids
zurück, die im Array enthalten sind.
Appointment.where(id: )# => returns all appointments with ids that are included in the array
Wir wissen, dass pluck
ein Array zurückgibt, also können wir ein Array konstruieren, das die Fremdschlüssel enthält, die wir im zugehörigen Modell erfassen wollen. Wenn wir zum Beispiel feststellen wollen, welche appointments
mit charges
verknüpft sind, können wir ein Array aus der Spalte appointment_id
der Tabelle charges
wie folgt erstellen:
Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like:
Um festzustellen, welche appointments
mit Gebühren verknüpft sind, können wir schreiben:
Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )
Und dies in einen Bereich des Modells Appointment
umwandeln:
class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }end
Wenn wir nun feststellen wollen, welche appointments
mit charges
verbunden sind, können wir schreiben:
Appointment.received_payment_info#=> #<ActiveRecord::Relation
Was die folgenden SQL-Abfragen erzeugt:
SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)
pluck
erlaubt uns:
- eine assoziierte Datenbanktabelle effizient abzufragen, um…
- ein Array aus der assoziierten Tabelle mit allen foreign_keys von Objekten aus der primären Tabelle zu generieren
- das Array zu verwenden, um zu bestimmen, welche Objekte in der primären Tabelle assoziierte Objekte in der sekundären Tabelle haben
Ich hoffe, Sie fanden dies hilfreich. Viel Spaß beim Zupfen und Auswählen.