Ruby on Rails: jak sortować według dwóch kolumn przy użyciu ActiveRecord?

94

Chcę sortować według dwóch kolumn, jedna to DateTime ( updated_at), a druga to Decimal (Price)

Chciałbym móc najpierw sortować według updated_at, a następnie, jeśli kilka pozycji występuje tego samego dnia, sortować według ceny.

NullVoxPopuli
źródło

Odpowiedzi:

66

Zakładając, że używasz MySQL,

Model.all(:order => 'DATE(updated_at), price')

Zwróć uwagę na różnicę w stosunku do innych odpowiedzi. updated_atKolumna będzie pełny znacznik czasu, więc jeśli chcesz porządek oparty na dzień została aktualizowana, trzeba użyć funkcji aby uzyskać tylko data część z datownik. To znaczy w MySQL DATE().

Daniel Vandersluis
źródło
7
Aby zatrzymać łączy z losowo zerwania z komunikatów „niejednoznaczne” kolumn, należy użyć następującego solidniejsze wersję: :order => ["DATE(#{table_name}.updated_at)", :price](zauważ, że :pricejest symbolem.)
Jo Liss
Musiałem uciec od kolumny z zamówieniami w ten ordersposób:Model.all(:order => "day asc, `order` asc")
grant
149

W Rails 4 możesz zrobić coś podobnego do:

Model.order(foo: :asc, bar: :desc)

fooi barsą kolumnami w bazie danych.

Christian Fazzini
źródło
1
Rails 4 jest najlepszy.
Darth Egregious
57
Thing.find(:all, :order => "updated_at desc, price asc")

da rade.

Aktualizacja:

Thing.all.order("updated_at DESC, price ASC")

jest droga Rails 3. (Dzięki @cpursley )

Erik Escobedo
źródło
4
Dziękuję @Erik - wiem, że ta odpowiedź jest stara, więc oto moje ostrzeżenie dla tych, którzy ją teraz widzą: Ta metoda została wycofana z Railsów 3.2. Zamiast tego użyj Thing.all =)
Abdo
Prawidłowo, to działało dobrze dla mnie: Thing.all.order("updated_at DESC, price ASC")
cpursley
1
Twoja zmiana było pomocne dla mnie, gdy potrzebowałem na małe posortowanych wartości: Thing.order("LOWER(name), number").
Nick
36

Interfejs kwerendy Active Record pozwala określić dowolną liczbę atrybutów w celu uporządkowania zapytania:

models = Model.order(:date, :hour, price: :desc)

lub jeśli chcesz uzyskać bardziej szczegółowe informacje (dzięki @ zw963 ):

models = Model.order(price: :desc, date: :desc, price: :asc) 

Bonus: po pierwszym zapytaniu możesz łączyć inne zapytania:

models = models.where('date >= :date', date: Time.current.to_date)
golfadas
źródło
Wiem, że to stary post, ale osobiście zmieniłbym modelna, modelsaby ktoś wiedział, że jest w liczbie mnogiej. Tylko sugestia.
Tass
1
Myślę, że powinienem edytować bardziej konkretny przykład: np. Models = Model.order ({price:: desc}, {date:: desc}, {price: asc})
zw963
jeśli ktoś to wkleił i zobaczył niezdefiniowany błąd metody, jest tu mała literówka. Powinien być :asczamiast asc:Model.order({price: :desc}, {date: :desc}, {price: :asc})
nayiaw
18

Właściwie jest na to wiele sposobów przy użyciu modułu Active Record. Jeden, o którym nie wspomniano powyżej, to (w różnych formatach, wszystkie prawidłowe):

Model.order(foo: :asc).order(:bar => :desc).order(:etc)

Może jest bardziej rozwlekły, ale osobiście łatwiej mi się nim zarządza. SQL jest tworzony tylko w jednym kroku:

SELECT "models".* FROM "models" ORDER BY "models"."etc" ASC, "models"."bar" DESC, "models"."foo" ASC

Tak więc w przypadku pierwotnego pytania:

Model.order(:updated_at).order(:price)

Nie musisz deklarować typu danych, ActiveRecord robi to płynnie, podobnie jak twój silnik DB

Ruby Racer
źródło
Działa to doskonale, kiedy za pomocą dwóch kolumn z dwóch różnych tabel, takich jak: Member.includes (: wyborców) .order ( "town_club mal") zamówienie ( "voters.last_name ASC").
bkunzi01
1
Czy opublikowany kod SQL odpowiada Model.order(foo: :asc).order(:bar => :desc).order(:etc)? Kolejność klauzul kolejności w SQL jest odwrotna do tego, co otrzymuję, gdy .to_sqlna tym uruchamiam .
Qaz,
1
@Qaz to było dawno temu. Myślę, że prawdopodobnie muszę to poprawić, nigdy nie zauważyłem. Jeszcze raz sprawdzę później. Dzięki.
Ruby Racer
2
Model.all(:order => 'updated_at, price')
robertokl
źródło
0

Żaden z nich nie zadziałał dla mnie! Po dokładnie 2 dniach szukania w internecie od góry do dołu znalazłem rozwiązanie!

powiedzmy, że masz wiele kolumn w tabeli produktów, w tym: cena_specjalna i msrp. To są dwie kolumny, według których próbujemy sortować.

OK, najpierw w swoim Modelu dodaj tę linię:

named_scope :sorted_by_special_price_asc_msrp_asc, { :order => 'special_price asc,msrp asc' }

Po drugie, w Kontrolerze produktu dodaj miejsce, w którym chcesz przeprowadzić wyszukiwanie:

@search = Product.sorted_by_special_price_asc_msrp_asc.search(search_params)
Max Alexander Hanna
źródło