2009-05-24 14 views
29

Ich mache eine statische Berechnung in meinem Produkt. Ein Benutzer hat eine Reihe von Operationen ausgeführt, sagen wir gepostete Kommentare. Ich möchte ihnen zeigen können, wie viele Kommentare sie pro Woche für den letzten Monat oder pro Monat für das vergangene Jahr gepostet haben.Gruppierung nach Woche/Monat/etc & ActiveRecord?

Gibt es eine Möglichkeit mit ActiveRecord auf diese Weise zu gruppieren? Ist es mein bestes, dies einfach manuell zu tun - um die Datensätze zu summieren, die auf meinen eigenen Kriterien basieren?

class User < ActiveRecord::Base 
    has_many :comments 
end 

class Comments < ActiveRecord::Base 
    belongs_to :user 
end 

@user.comments(:all).map {|c| ...do my calculations here...} 

oder gibt es einen besseren Weg?

danke!

@user.comments.count(:group => "year(created_at),month(created_at)") 

Dry-Code, ymmv

Antwort

26

In diesem Fall war die beste Lösung für mich entweder in geraden SQL es tun, oder die Active group_by Funktion zu verwenden:

@user.all.group_by{ |u| u.created_at.beginning_of_month } 
+10

'group_by' ist keine ActiveRecord-Methode, sondern eine Ruby-Methode für' Enumerable'. – Laurens

+0

Die Verwendung von 'u.created_at.month' ist kürzer –

+11

Bitte nicht, dass dies alle Datensätze aus der Datenbank lädt, ActiveRecord Objekte instanziiert, Daten in ActiveSupports zeitzonenbewusste Objekte analysiert - alles nur um die Anzahl der Datensätze zu berechnen. –

13

würde Meine Vermutung etwas ähnliches sein.

+0

Ich glaube, dass wird über Monate auch über Jahre gruppiert - also, wenn Sie zwei Jahre Daten haben, alle Sachen im Januar Jahr 1 und Jahr 2. Was ich suche, ist eine Art zu erzählen für eine 24 Monatsfenster zum Beispiel, wie viele pro Monat. – teich

+0

Sie könnten eine Bedingung hinzufügen, um das Jahr auch zu begrenzen, wie: conditions => [: created_at, "> # {24.months.ago}"]. Nochmals ungeprüft, sollte aber mit so etwas möglich sein. –

+0

Dies scheint mysql spezifische – Tachyons

2

Schauen Sie sich die has_activity Plugin: Oren

+0

Danke für den Zeiger. Sieht aus wie has_activity ist nur mysql. Mein Produktions-Host ist postgresql. – teich

66

In Postgres Sie tun können:

@user.comments.group("DATE_TRUNC('month', created_at)").count 

zu erhalten:

{"2012-08-01 00:00:00"=>152, "2012-07-01 00:00:00"=>57, "2012-09-01 00:00:00"=>132} 

Es Werte von „Mikrosekunden“ bis „Jahrtausend“ für die Gruppierung akzeptiert:

+4

So viel schneller als mit Ruby enumerable group_by! –

+0

Wojtek, was ist, wenn in einem Monat nichts erschaffen wurde? Sie bekommen nichts für diesen Monat. –

+1

@MattSmith Ich glaube schon. Glücklicherweise ist es einfach, beim Lesen von Werten aus der Ausgabe dieser Abfrage einen Standardwert anzugeben: '' 'output.fetch (" 2012-08-01 00:00:00 ", 0)' '' –

16

Hier ist die verfeinerte Version dieses

@user.comments.group("year(created_at)").group("month(created_at)").count 
4

Verwenden group_by

@user.comments.group_by(&:week) 

class User < ActiveRecord::Base 
    def week 
    some_attribute_like_date.strftime('%Y-%W') 
    end 
end 

Dies gibt Ihnen eine gruppierte Liste im Format YYYY-WW

2

Check out die Gruppe date gem

https://github.com/ankane/groupdate

es hat kürzlich commits, arbeitet mit postgresql, integriert sich leicht mit chart kick für schnelle charterung, und arbeitet mit zeitzonen !!

+0

GroupDate funktioniert nur mit UTC. Wenn Sie eine andere Zeitzone in Ihrer Datenbank verwenden, sollten Sie Alternativen in Betracht ziehen. – msdundar

Verwandte Themen