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

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 taas Model.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-kyselyn SELECT-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, kuten select. 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 rakentamatta ActiveRecord-objektia, se on suorituskykyisempi kuin select.

Mutta se, että pluck palauttaa massan, tarkoittaa, että et voi ketjuttaa tavallisia ActiveRecord-kyselyitä pluck:n päälle. Se palauttaa NoMethodError:

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

Mutta pluck toimii ActiveRecord-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:a ActiveRecord malliobjektien rajaamiseen määrittääkseni, mihin malliobjekteihin liittyy tietueita jossakin toisessa taulussa.

Vastaanottakaamme esimerkiksi seuraava luokka:

class Appointment < ActiveRecord::Base
has_many :chargesend

Jos haluamme määrittää, millä appointments on charges ja millä ei, voimme käyttää pluck:a scope:ssa. Näin menetellään:

Aluksi on muistettava, että Model.where(field: value):n kohdalla value voi olla joko yksittäinen objekti (kuten integer, string jne.) tai se voi olla array objektien array joukko.

Siten seuraava on kelvollinen ja palauttaa kaikki appointments:t, joilla on ids ja jotka sisältyvät joukkoon.

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

Nyt 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 assosioituneet charges:iin, voimme luoda matriisin charges-taulukon appointment_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)) }end

Siten nyt, kun haluamme määrittää, mihin appointments liittyy charges, voimme kirjoittaa:

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

joka 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:

  1. tehokkaasti kysyä assosioituneelta tietokantataululta…
  2. luoda assosioituneesta taulusta joukko, jossa on kaikki ensisijaisen taulun objektien vieraat_avaimet
  3. 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.

Vastaa

Sähköpostiosoitettasi ei julkaista.