Column Down
select
i pluck
są dwoma różnymi i użytecznymi sposobami zwracania wartości z jednej lub więcej kolumn w tabeli bazy danych jako kolekcji. Na przykład, wyobraź sobie, że masz tabelę questions
w swojej bazie danych. Każda question
może mieć trzy pola: id
, question_text
, oraz foreign_key
z powiązanej tabeli. Aby zwrócić wartości tylko z kolumny question_text
, użyłbyś select
lub pluck
. Chciałbym zbadać różnice między tymi dwiema metodami i zakończyć zastosowaniem pluck
wewnątrz aplikacji Rails.
Select
select
działa na dwa unikalne sposoby:
i.select
przyjmuje blok i działa tak samo jak Array#select
.
Model.all.select { |m| m.field == value }
Buduje tablicę obiektów Ruby z bazy danych dla zakresu, konwertując je na tablicę i iterując przez nie za pomocą Array#select
.
select
vswhere
Przekazanie bloku do
select
z dużym zestawem danych (tj. wieloma wierszami) jest wolniejsze niż użycie innych strategii, takich jakwhere
:
Model.where(field: value)
ponieważ w przypadku
Model.all.select { |m| m.field == value }
, Railsy najpierw przekonwertują wszystkie wiersze tabeli na obiekty Ruby, a następnie uruchomią dany blok dla każdego obiektu Ruby, podczas gdyModel.where(field: value)
generuje instrukcję SQL, która odciąża SQL, który jest szybszy niż Ruby dla tego typu filtrowania.
ii. select
modyfikuje instrukcję SELECT
dla zapytania SQL tak, że tylko niektóre pola są pobierane:
Model.select(:field)
# =>
Na przykład, z mojego projektu:
Question.select(:question_text)
# => #<ActiveRecord::Relation >
To generuje następujący SQL:
SELECT "questions"."question_text" FROM "questions"
Zauważ, że w tym drugim przykładzie, metoda select
nie zwraca tablicy; zwraca obiekt ActiveRecord::Relation. W rezultacie, można do niej podłączyć inne metody ActiveRecord::QueryMethods. Na przykład:
Question.select(:question_text).limit(5)# => #<ActiveRecord::Relation >
Generuje to następujący SQL:
SELECT "questions"."question_text" FROM "questions" LIMIT ? ]
Pluck
Z przewodnika po Railsach:
pluck
może być użyty do zapytania o pojedyncze lub wiele kolumn z bazowej tabeli modelu. Przyjmuje listę nazw kolumn jako argument i zwraca tablicę wartości określonych kolumn z odpowiadającym im typem danych.
Ważnym punktem jest to, że pluck
zwraca tablicę. Nie zwraca on obiektu ActiveRecord::Relation, jak select
. Tak więc, na przykład:
Question.pluck(:question_text)# => # this returns an array with all of the values from the question_text column from the questions table.
Ponieważ pluck
przekształca wynik zapytania do bazy danych w tablicę Ruby bez konstruowania obiektu ActiveRecord
, jest bardziej wydajne niż select
.
Jednakże fakt, że pluck
zwraca tablicę oznacza, że nie można łączyć standardowych zapytań ActiveRecord
z pluck
. Takie zapytanie zwróci NoMethodError
:
Question.pluck(:question_text).limit(5)# => NoMethodError: undefined method `limit' for #<Array:0x007fc5c1dfb3b0>
Ale pluck
działa na obiektach ActiveRecord
, więc poniższe zapytanie zwróci oczekiwany wynik:
Question.limit(5).pluck(:question_text)#=>
pluck
może przyjmować wiele argumentów, aby skonstruować wielowymiarową tablicę:
Question.pluck(:question_text, :course_id)#=> , , ...]
Kiedy użyłbym Pluck?
Użyłem pluck
do zakresu ActiveRecord
obiektów modelu, aby określić, które obiekty modelu mają powiązane rekordy w innej tabeli.
Na przykład weźmy następującą klasę:
class Appointment < ActiveRecord::Base
has_many :chargesend
Jeśli chcemy określić, które appointments
mają charges
, a które nie, możemy użyć pluck
w scope
. Oto jak:
Po pierwsze, pamiętaj, że dla Model.where(field: value)
, value
może być albo pojedynczym obiektem (jak integer
, string
, itd.), albo może być array
obiektów.
Więc, poniższe jest ważne i zwróci wszystkie appointments
z ids
, które są zawarte w tablicy.
Appointment.where(id: )# => returns all appointments with ids that are included in the array
Wiemy, że pluck
zwraca tablicę, więc możemy skonstruować tablicę, która zawiera klucze obce, które chcemy określić w powiązanym modelu. Na przykład, jeśli chcemy określić, które appointments
mają powiązane charges
, możemy utworzyć tablicę z kolumny appointment_id
tabeli charges
, tak jak to:
Charge.pluck(:appointment_id)# => returns an array with all of the appointment_ids from the charges table, like:
Aby określić, które appointments
mają powiązane opłaty, możemy napisać:
Appointment.where(id: Charge.pluck(:appointment_id))# this is the same as Appointment.where(id: )
A przekształcając to w zakres na modelu Appointment
:
class Appointment < ActiveRecord::Base
has_many :charges scope :received_payment_info, -> {
where(id: Charge.pluck(:appointment_id)) }end
Teraz więc, gdy chcemy określić, które appointments
mają powiązane charges
, możemy napisać:
Appointment.received_payment_info#=> #<ActiveRecord::Relation
, co generuje następujące zapytania SQL:
SELECT "charges"."appointment_id" FROM "charges"SELECT "appointments".* FROM "appointments" WHERE ("appointments"."id" IN (35, 44, 82) OR "appointments"."id" IS NULL)
pluck
pozwoliło nam na:
- wydajne odpytywanie stowarzyszonej tabeli bazy danych, aby…
- generować tablicę z tabeli stowarzyszonej zawierającą wszystkie klucze obce obiektów z tabeli podstawowej
- wykorzystać tę tablicę do określenia, które obiekty w tabeli podstawowej mają powiązane obiekty w tabeli drugorzędnej
Mam nadzieję, że uznałeś to za pomocne. Ciesz się skubaniem i wybieraniem.