Column Down
select
ja pluck
ovat kaksi erilaista ja hyödyllistä tapaa palauttaa tietokantataulukon yhden tai useamman sarakkeen arvot kokoelmana. Kuvittele esimerkiksi, että tietokannassasi on questions
-taulu. Jokaisessa question
-sarakkeessa saattaa olla kolme kenttää: id
, question_text
ja foreign_key
siihen liittyvästä taulusta. Jos haluat palauttaa vain question_text
-sarakkeen arvot, käyttäisit select
tai pluck
. Haluaisin tutkia näiden kahden menetelmän eroja ja päätteeksi esitän pluck
:n sovelluksen Rails-sovelluksen sisällä.
Select
select
toimii kahdella ainutlaatuisella tavalla:
i.select
ottaa lohkon ja toimii aivan kuten Array#select
.
Model.all.select { |m| m.field == value }
Tämä muodostaa Ruby-objektien joukon tietokannasta soveltamisalaa varten, muuntaa ne joukoksi ja iteroi niiden läpi Array#select
:n avulla.
select
vs.where
Lohkon syöttäminen
select
:iin, jossa on suuri tietomäärä (esim. monia rivejä) on hitaampaa kuin muiden strategioiden, kutenwhere
:
Model.where(field: value)
, koska
Model.all.select { |m| m.field == value }
:n avulla Rails muuntaa ensin kaikki taulukon rivit Ruby-objekteiksi ja ajaa sitten annetun lohkon kullekin Ruby-objektille, kun taasModel.where(field: value)
luo SQL-lausekkeen, joka siirtää raskaan työn SQL:n tehtäväksi, joka on nopeampi kuin Ruby tämäntyyppisessä suodatuksessa.select
muuttaa SQL-kyselynSELECT
-lauseen niin, että vain tietyt kentät haetaan:Model.select(:field)
# =>Esimerkiksi eräästä projektistani:
Question.select(:question_text)
# => #<ActiveRecord::Relation >Tämä tuottaa seuraavan SQL:n:
SELECT "questions"."question_text" FROM "questions"Huomaa, että tässä jälkimmäisessä esimerkissä
select
-metodi ei palauta matriisia, vaan ActiveRecord::Relation-olion. Tämän seurauksena voit ketjuttaa siihen muita ActiveRecord::QueryMethodeja. Esimerkiksi:Question.select(:question_text).limit(5)# => #<ActiveRecord::Relation >Tämä tuottaa seuraavan SQL:n:
SELECT "questions"."question_text" FROM "questions" LIMIT ? ]Pluck
Rails-oppaista:
pluck
voidaan käyttää yksittäisten tai useiden sarakkeiden kyselyyn mallin taustalla olevasta taulukosta. Se hyväksyy argumenttina listan sarakkeiden nimiä ja palauttaa määritettyjen sarakkeiden arvojen joukon vastaavalla tietotyypillä.Tärkeää tässä on se, että
pluck
palauttaa joukon. Se ei palauta ActiveRecord::Relation-oliota, kutenselect
. Eli esimerkiksi:Question.pluck(:question_text)# => # this returns an array with all of the values from the question_text column from the questions table.Koska
pluck
muuntaa tietokantakyselyn tuloksen Ruby-massaksi rakentamattaActiveRecord
-objektia, se on suorituskykyisempi kuinselect
.Mutta se, että
pluck
palauttaa massan, tarkoittaa, että et voi ketjuttaa tavallisiaActiveRecord
-kyselyitäpluck
:n päälle. Se palauttaaNoMethodError
:Question.pluck(:question_text).limit(5)# => NoMethodError: undefined method `limit' for #<Array:0x007fc5c1dfb3b0>Mutta
pluck
toimiiActiveRecord
-objekteilla, joten seuraava palauttaa odotetun tuloksen:Question.limit(5).pluck(:question_text)#=>
pluck
voi ottaa useita argumentteja muodostaakseen moniulotteisen joukon:Question.pluck(:question_text, :course_id)#=> , , ...]Milloin käyttäisin Pluckia ?
Olen käyttänyt
pluck
:aActiveRecord
malliobjektien rajaamiseen määrittääkseni, mihin malliobjekteihin liittyy tietueita jossakin toisessa taulussa.Vastaanottakaamme esimerkiksi seuraava luokka:
class Appointment < ActiveRecord::Base
has_many :chargesendJos haluamme määrittää, millä
appointments
oncharges
ja millä ei, voimme käyttääpluck
:ascope
:ssa. Näin menetellään:Aluksi on muistettava, että
Model.where(field: value)
:n kohdallavalue
voi olla joko yksittäinen objekti (kuteninteger
,string
jne.) tai se voi ollaarray
objektienarray
joukko.Siten seuraava on kelvollinen ja palauttaa kaikki
appointments
:t, joilla onids
ja jotka sisältyvät joukkoon.Appointment.where(id: )# => returns all appointments with ids that are included in the arrayNyt tiedämme, että
pluck
palauttaa joukon, joten voimme muodostaa joukon, joka sisältää ne vieraat avaimet, jotka haluamme sisällyttää siihen liittyvään malliin. Jos esimerkiksi haluamme määrittää, mitkäappointments
ovat assosioituneetcharges
:iin, voimme luoda matriisincharges
-taulukonappointment_id
-sarakkeesta seuraavasti:Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like:Mitäksemme, mitkä
appointments
ovat assosioituneet maksuihin, voimme kirjoittaa:Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )Ja muuntamalla tämä
Appointment
-mallin laajuudeksi:class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }endSiten nyt, kun haluamme määrittää, mihin
appointments
liittyycharges
, voimme kirjoittaa:Appointment.received_payment_info#=> #<ActiveRecord::Relationjoka tuottaa seuraavat SQL-kyselyt:
SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)
pluck
sallii meidän:
- tehokkaasti kysyä assosioituneelta tietokantataululta…
- luoda assosioituneesta taulusta joukko, jossa on kaikki ensisijaisen taulun objektien vieraat_avaimet
- käyttää tuota joukkoa määrittääksemme, mitkä ensisijaisen taulun objektit ovat assosioituneita objekteja toissijaisessa taulussa
Toivon, että tästä oli apua. Nauti nyppimisestä ja valitsemisesta.