Column Down
select
és pluck
két különböző és hasznos módja annak, hogy egy adatbázis-tábla egy vagy több oszlopának értékeit gyűjteményként adjuk vissza. Képzeljük el például, hogy van egy questions
tábla az adatbázisban. Minden question
-nek három mezője lehet: id
, question_text
és egy foreign_key
egy kapcsolódó táblából. Ha csak a question_text
oszlop értékeit szeretné visszaadni, akkor a select
vagy a pluck
értéket használná. Szeretném megvizsgálni a két módszer közötti különbségeket, és a pluck
egy Rails-alkalmazáson belüli alkalmazásával fejezem be.
Select
select
két egyedi módon működik:
i.select
egy blokkot vesz fel, és ugyanúgy működik, mint a Array#select
.
Model.all.select { |m| m.field == value }
Ez a Ruby objektumok egy tömbjét építi fel az adatbázisból a hatókör számára, tömbtá alakítja őket, és a Array#select
segítségével iterálja őket.
select
vswhere
A blokk átadása a
select
-ba egy nagy adathalmazzal (pl. sok sor) lassabb, mint más stratégiák használata, mint például awhere
:
Model.where(field: value)
mert a
Model.all.select { |m| m.field == value }
esetén a Rails először az összes táblázat sort Ruby objektumokká alakítja, majd lefuttatja az adott blokkot minden egyes Ruby objektumhoz, míg aModel.where(field: value)
egy SQL utasítást generál, amely a nehéz munkát az SQL-re hárítja, ami gyorsabb, mint a Ruby az ilyen típusú szűrésnél.
ii. A select
úgy módosítja az SQL-lekérdezés SELECT
utasítását, hogy csak bizonyos mezőket kérjen le:
Model.select(:field)
# =>
Egy saját projektemből például:
Question.select(:question_text)
# => #<ActiveRecord::Relation >
Ez a következő SQL-t generálja:
SELECT "questions"."question_text" FROM "questions"
Megjegyezzük, hogy ebben a második példában a select
módszer nem egy tömböt ad vissza, hanem egy ActiveRecord::Relation objektumot. Ennek eredményeképpen más ActiveRecord::QueryMethodokat láncolhat hozzá. Például:
Question.select(:question_text).limit(5)# => #<ActiveRecord::Relation >
Ez a következő SQL-t generálja:
SELECT "questions"."question_text" FROM "questions" LIMIT ? ]
Pluck
A Rails útmutatókból:
pluck
egy vagy több oszlop lekérdezésére használható egy modell mögöttes táblájából. Érvként egy oszlopnevekből álló listát fogad el, és a megadott oszlopok értékeinek egy tömbjét adja vissza a megfelelő adattípussal.
A fontos pont itt az, hogy a pluck
egy tömböt ad vissza. Nem egy ActiveRecord::Relation objektumot ad vissza, mint a select
. Tehát például:
Question.pluck(:question_text)# => # this returns an array with all of the values from the question_text column from the questions table.
Mert mivel a pluck
egy adatbázis-lekérdezés eredményét egy Ruby-tömbté alakítja át anélkül, hogy egy ActiveRecord
objektumot építene fel, ez nagyobb teljesítményű, mint a select
.
Az azonban, hogy a pluck
egy tömböt ad vissza, azt jelenti, hogy a pluck
-re nem lehet szabványos ActiveRecord
lekérdezéseket láncolni. Ennek megtétele egy NoMethodError
:
Question.pluck(:question_text).limit(5)# => NoMethodError: undefined method `limit' for #<Array:0x007fc5c1dfb3b0>
Viszont a pluck
működik ActiveRecord
objektumokon, így a következő a várt eredményt fogja visszaadni:
Question.limit(5).pluck(:question_text)#=>
pluck
több argumentumot is elfogadhat egy többdimenziós tömb felépítéséhez:
Question.pluck(:question_text, :course_id)#=> , , ...]
Mikor használnám a Pluck-ot ?
Az pluck
segítségével ActiveRecord
modellobjektumokat határoltunk le, hogy meghatározzuk, mely modellobjektumokhoz tartoznak rekordok egy másik táblázatban.
Vegyük például a következő osztályt:
class Appointment < ActiveRecord::Base
has_many :chargesend
Ha meg akarjuk határozni, hogy melyik appointments
rendelkezik charges
és melyik nem, akkor használhatjuk a pluck
-t egy scope
-ban. Íme, hogyan:
Először is, ne feledjük, hogy a Model.where(field: value)
esetében a value
lehet egyetlen objektum (mint integer
, string
stb.), vagy lehet egy array
objektumokból álló array
.
Az alábbiak tehát érvényesek, és az összes appointments
ids
-t tartalmazó appointments
-t visszaadják, amelyek a tömbben szerepelnek.
Appointment.where(id: )# => returns all appointments with ids that are included in the array
Hát, tudjuk, hogy a pluck
egy tömböt ad vissza, így létrehozhatunk egy olyan tömböt, amely tartalmazza azokat az idegen kulcsokat, amelyeket a kapcsolódó modellben hatókörbe akarunk vonni. Például, ha meg akarjuk határozni, hogy melyik appointments
-hoz tartozik charges
, akkor létrehozhatunk egy tömböt a charges
tábla appointment_id
oszlopából, így:
Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like:
Hogy meghatározzuk, melyik appointments
-hoz tartoznak díjak, azt írhatjuk:
Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )
És ezt átalakítva a Appointment
modell hatókörévé:
class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }end
Így most, amikor meg akarjuk határozni, hogy melyik appointments
-hoz van társítva charges
, írhatjuk:
Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )
Azt, hogy melyik appointments
-hoz van társítva charges
, leírhatjuk:
Appointment.received_payment_info#=> #<ActiveRecord::Relation
amely a következő SQL-lekérdezéseket generálja:
SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)
pluck
lehetővé tette számunkra:
- hatékonyan lekérdezni egy kapcsolódó adatbázis táblát, hogy…
- generáljunk egy tömböt a kapcsolódó táblából az elsődleges tábla objektumainak összes idegen_kulcsával
- felhasználjuk ezt a tömböt annak meghatározására, hogy az elsődleges tábla mely objektumai rendelkeznek kapcsolódó objektumokkal a másodlagos táblában
Remélem, hasznosnak találtad ezt. Jó szórakozást a szedegetéshez és a kiválasztáshoz.