Jak pobrać wartości z pojedynczej kolumny do tablicy

80

W tej chwili robię coś takiego, aby wybrać jedną kolumnę danych:

points = Post.find_by_sql("select point from posts")

Następnie przekazując je do metody, chciałbym, aby moja metoda pozostała agnostyczna i teraz muszę wywoływać hash.point z mojej metody. Jak mogę szybko przekonwertować to na tablicę i przekazać zestaw danych do mojej metody, czy jest lepszy sposób?

franklin stine
źródło

Odpowiedzi:

190

W Railsach 3.2 jest do tego metoda wyrywania

Takie jak to:

Person.pluck(:id) # SELECT people.id FROM people
Person.pluck(:role).uniq # unique roles from array of people
Person.distinct.pluck(:role) # SELECT DISTINCT role FROM people SQL
Person.where(:confirmed => true).limit(5).pluck(:id)

Różnica między uniq i clear

alony
źródło
W jaki sposób tablica może dziedziczyć kolejność wyników zapytania za pomocą pluck?
franklin stine
3
Post.order (: score) .pluck (: score) jest rozwiązaniem. Dzięki.
franklin stine
6
Rwać identyfikatory istnieje specjalna metoda: Person.ids.
shock_one
Zajrzyj także do klejnotu Erniego Millera Valium github.com/ernie/valium, zwłaszcza jeśli korzystasz ze starszych Railsów lub chcesz mieć wiele kolumn
James Daniels,
Od wersji Rails 5.0 zaleca się używanie distinctzamiast uniq: takPerson.distinct.pluck(:role)
David
15

Powinieneś użyć pluckmetody zgodnie z sugestią @alony. Jeśli utkniesz przed Railsami 3.2, możesz użyć selectmetody ActiveRecord razem z Array#map:

Post.select(:point).map(&:point)
#=> ["foo", "bar", "baz"] 

przed Rubim 1.9 musiałbyś to zrobić .map{|x| x.title}, ponieważ Symbol#to_proc(aliasowany przez jednoargumentowy &operator) nie jest zdefiniowany we wcześniejszych wersjach Rubiego.

Patrick Oscity
źródło
Dzięki. Widziałem, jak skomentowałeś nową metodę Pluck. Czy możesz z tym zrobić to samo?
franklin stine
Tak, jeśli uważnie przeczytasz odpowiedź @ alony, zauważysz, że podała już przykład, który to robi.
Patrick Oscity,
5

Jeśli widzisz definicję select_values, to za pomocą „map (&: field_name)”

  def select_values(arel, name = nil)
    result = select_rows(to_sql(arel), name)
    result.map { |v| v[0] }
  end

Typowy i ogólny sposób gromadzenia wszystkich wartości pól w tablicy przez Railsy wygląda następująco:

points = Post.all(:select => 'point').map(&:point)
Vik
źródło
Słuszna uwaga. Dziękuję Ci. Działa to świetnie i pozwala mi nadal stosować kolejność i inne elementy do zapytania, w przeciwieństwie do przykładu Post.select.
franklin stine
Nie zgadzam się z tobą, @franklinstine: Post.select(:point).limit(1)wykonuje, SELECT point FROM "posts" LIMIT 1a Post.all(:select => :point).limit(1)podnosi NoMethodError. Proszę popraw mnie jeżeli się mylę.
Patrick Oscity,
Zgadzam się z twoimi komentarzami. Ale nie dostaję tam, gdzie wspomniano w poście, aby użyć: Post.all (: select =>: point) .limit (1) Oczywiście spowoduje to błąd „undefined method 'limit'”
Vik
@franklinstine powiedział, że woli twoją metodę, ponieważ mógłby połączyć inne stwierdzenia po niej, chciałem tylko wyjaśnić, że to nieprawda
Patrick Oscity
Tak @padde źle wywnioskowałeś. Mówiłem, że nadal możesz zastosować kolejność i inne zapytania, takie jak: Post.all (: select => 'score',: order => 'score ASC'). Map (&: score).
franklin stine
2
points = Post.all.collect {|p| p.point}
rajibchowdhury
źródło
2
To działa, ale wybierasz wszystkie pola z bazy danych, a następnie filtrujesz wynik w Rubim, podczas gdy selectinstrukcja pobiera tylko określone kolumny.
Patrick Oscity,