select och pluck är två olika och användbara sätt att returnera värdena från en eller flera kolumner i en databastabell som en samling. Tänk dig till exempel att du har en questions-tabell i din databas. Varje question kan ha tre fält: id, question_text och ett foreign_key från en associerad tabell. Om du vill returnera värdena från endast kolumnen question_text skulle du använda select eller pluck. Jag vill utforska skillnaderna mellan dessa två metoder och avsluta med en tillämpning av pluck i en Rails-applikation.

Select

select fungerar på två unika sätt:

i.select tar ett block och fungerar precis som Array#select.

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

Detta bygger upp en array av Ruby-objekt från databasen för räckvidden, omvandlar dem till en array och itererar genom dem med hjälp av Array#select.

select vs where

Förmedla ett block till select med en stor datamängd (dvs. många rader) är långsammare än att använda andra strategier, som where:

Model.where(field: value)

för att med Model.all.select { |m| m.field == value } konverterar Rails först alla tabellrader till Ruby-objekt och kör sedan det givna blocket för varje Ruby-objekt, medan Model.where(field: value) genererar ett SQL-uttalande som avlastar SQL från det tunga arbetet, vilket är snabbare än Ruby för den här typen av filtrering.

ii. select ändrar SELECT-angivelsen för SQL-frågan så att endast vissa fält hämtas:

Model.select(:field)
# =>

Till exempel från ett av mina projekt:

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

Detta genererar följande SQL:

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

Bemärk att i det här andra exemplet returnerar select-metoden inte en matris, den returnerar ett ActiveRecord::Relation-objekt. Därför kan du kedja andra ActiveRecord::QueryMethods till den. Till exempel:

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

Detta genererar följande SQL:

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

Pluck

Från Rails Guides:

pluck kan användas för att fråga efter en eller flera kolumner från den underliggande tabellen i en modell. Den tar emot en lista med kolumnnamn som argument och returnerar en array av värden för de angivna kolumnerna med motsvarande datatyp.

Den viktiga punkten här är att pluck returnerar en array. Den returnerar inte ett ActiveRecord::Relation-objekt, som select. Så, till exempel:

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

pluck omvandlar resultatet av en databasfråga till en Ruby-array utan att konstruera ett ActiveRecord-objekt är den mer effektiv än select.

pluck returnerar en array innebär det dock att du inte kan kedja standard ActiveRecord-frågor på pluck. Om du gör det kommer du att få en NoMethodError:

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

Men pluck fungerar på ActiveRecord-objekt, så följande kommer att ge det förväntade resultatet:

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

pluck kan ta emot flera argument för att konstruera en flerdimensionell array:

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

När skulle jag använda Pluck?

Jag har använt pluck för att avgränsa ActiveRecord modellobjekt för att avgöra vilka modellobjekt som har associerade poster i en annan tabell.

Titta till exempel följande klass:

class Appointment < ActiveRecord::Base
has_many :chargesend

Om vi vill avgöra vilka appointments som har charges och vilka som inte har det, kan vi använda pluck i en scope. Så här gör vi:

För det första ska du komma ihåg att för Model.where(field: value) kan value antingen vara ett enskilt objekt (som integer, string etc.), eller så kan det vara en array av objekt.

Så följande är giltigt och returnerar alla appointments med ids som ingår i matrisen.

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

Vi vet att pluck returnerar en array, så vi kan konstruera en array som innehåller de främmande nycklar som vi vill ha räckvidd för i den associerade modellen. Om vi till exempel vill bestämma vilka appointments som har associerat charges kan vi skapa en array från kolumnen appointment_id i tabellen charges, så här:

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

För att bestämma vilka appointments som har associerade avgifter kan vi skriva:

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

Och konvertera detta till ett scope på Appointment-modellen:

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

Så när vi nu vill bestämma vilka appointments som har associerade charges, kan vi skriva:

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

vilket genererar följande SQL-frågor:

SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)

pluck vilket gör att vi kan:

  1. på ett effektivt sätt fråga en associerad databastabell för att…
  2. generera en matris från den associerade tabellen med alla foreign_keys för objekt från den primära tabellen
  3. använda den matrisen för att avgöra vilka objekt i den primära tabellen som har associerade objekt i den sekundära tabellen

Jag hoppas att du tyckte att det här var till hjälp. Lycka till med att plocka och välja ut.

Lämna ett svar

Din e-postadress kommer inte publiceras.