2016-05-04 6 views
-2

Profile können Beiträge erstellen. Profile können Beiträge kommentieren. Gewichtung: Post = 1, Kommentar = 1.Rails - Auflistung der meisten aktiven Profil basierend auf der Anzahl der Beiträge, Kommentare

Ich muss Personen basierend auf konsolidierte Gewichtung der Beiträge, Kommentare innerhalb letzten Monats auflisten.

, was ich versucht habe, ist:

profiles = Profile.find(:all, :include => [:posts, :comments], :conditions => ["posts.created_at > ? or comments.created_at > ?", 1.month.ago, 1.month.ago], :group => "profiles.id", :group => 'profiles.id, posts.id, comments.id', :limit => 5) 

und

sql = "SELECT DISTINCT profiles.id, count(posts.id) + count(comments.id) as pcount FROM profiles LEFT OUTER JOIN posts ON posts.profile_id = profiles.id LEFT OUTER JOIN comments ON comments.profile_id = profiles.id WHERE (posts.created_at > '#{1.month.ago}' and posts or comments.created_at > '#{1.month.ago}') GROUP BY profiles.id Order by pcount" 
profiles = ActiveRecord::Base.connection.execute(sql) 
+0

Sie können zwei Attribute in Ihrer Profiltabelle haben:: comments_count &: posts_count, Und jedes Mal, wenn ein Benutzer einen Beitrag oder Kommentar schreibt, können Sie Rails-Callbacks verwenden, um diese Werte zu erhöhen. –

+0

In diesem Fall konnten wir den Zeitpunkt des Posts oder Kommentars nicht lesen. Ich brauche die Liste der Top-Beitragenden des letzten Monats. –

Antwort

0

Ich schlage vor, wir LEFT JOIN auf beiden auf dem created_at Datum konditionierten Tabellen und die Gesamtzahl der nicht NULL Werte für jeden unabhängig zählen als ein neues Feld mit der Bezeichnung total_weight:

profiles = Profile.joins("LEFT JOIN posts ON posts.profile_id = profiles.id AND posts.created_at > ? LEFT JOIN comments ON comments.profile_id = profiles.id AND comments.created_at > ?", 1.month_ago, 1.month_ago).group("profiles.id").select("profiles.*, sum(posts.id IS NOT NULL) + sum(comments.id IS NOT NULL) as total_weight") 

Sie können "total_weight" in order und having Klauseln verwenden, und Sie können es in den Ergebnissen verweisen: profiles.first.total_weight.

Ich würde in Betracht ziehen, die entsprechenden Zählungen oder Gesamtzählung in einer neuen Spalte auf profiles zu halten, um diese Abfrage schneller und einfacher zu pflegen. Sie könnten eine Aufgabe haben, die täglich ausgeführt wird, um sie für jedes Profil zu aktualisieren. Auf diese Weise muss der Controller, der die Datensätze abrufen muss, diese Berechnung nicht jedes Mal einleiten.

+0

mit zusätzlichen Feldern wird in dieser Situation nicht helfen, da wir die Zeit von Post/Kommentar betrachten. –

+0

Also, was ist mit der vorgeschlagenen Join? –

+0

Und der Punkt über die zusätzlichen Felder, wenn Sie eine Offline-Aufgabe haben, die beispielsweise einmal am Tag ausgeführt wird, um sie zu aktualisieren. Wir machen das in unserer App ein paar Plätze; B. eine Zustandsspalte auf "Versteckt" aktualisieren, wenn sich ein Objekt in einem Satz anderer Zustände befindet und nicht für zwei Wochen aktualisiert wird. Auf diese Weise muss die Abfrage, die auf unserer Haupt-Zielseite ausgeführt wird, keine Daten vergleichen, was sehr langsam ist, sondern nur mit einer indizierten Statusspalte verglichen wird, die offline aktualisiert wird. –

0

ein Modell erstellen Activities mit Spalten month, 'comments_count', 'posts_count','profile_id' so dass

In Ihrem profile.rb Sie

has_many :activities 

und activity.rb haben, haben Sie

belongs_to :profile 

des Monats An jedem Ende mit whenever gem, führen Sie einen Job aus, der diese Zahlen berechnet und Werte für jeden Benutzer hinzufügt.

Vorteile:

  1. Sie können pro Monat Anzahl aller Profil Aktivitäten halten.
  2. Dies speichert Ihre Ausgabe und vereinfacht Ihre Abfrage drastisch. Sie müssen nur tun: profile.activities.where(month: Date.today.month - 1.month).

PS: Sie können die Abfrage verbessern

Nachteile: 1. Es wird schwierig sein zu halten, wie die Zeit vergeht und Profil zu.

Wenn Sie nur eine Zählung für letzten Monat behalten möchten, wird diese Con einfach gelöst werden.

Verwandte Themen