Wenn es Ihnen nichts ausmacht, sich mit ein bisschen SQL die Hände schmutzig zu machen, können Sie ein Fensterfunktion um die Arbeit zu erledigen. Sie können die Beitrags-IDs mit diesem SQL abrufen:
select id
from (
select id,
rank() over (partition by thread_id order by created_at desc)
from posts
where receiver_id = #{user.id}
) as dt
where rank = 1
Wenn Sie mehr Spalten wünschen, fügen Sie diese beiden SELECT-Klauseln hinzu. Der #{user.id}
ist natürlich der Empfänger, an dem Sie interessiert sind.
Der interessante Teil ist die Fensterfunktion:
rank() over (partition by thread_id order by created_at desc)
Dadurch wird die Tabelle basierend auf thread_id
in Gruppen aufgeteilt (eine Art lokalisiertes GROUP BY), ordnen Sie sie nach Zeitstempel (neueste zuerst) und dann nach rank()
ergibt 1 für den ersten Eintrag in jeder Gruppe, 2 für den zweiten usw.
Gegeben sei eine Tabelle, die so aussieht:
=> select * from posts;
id | receiver_id | thread_id | created_at
----+-------------+-----------+---------------------
1 | 1 | 2 | 2011-01-01 00:00:00
2 | 1 | 2 | 2011-02-01 00:00:00
3 | 1 | 2 | 2011-03-01 00:00:00
4 | 1 | 3 | 2011-01-01 00:00:00
5 | 1 | 4 | 2011-01-01 00:00:00
6 | 1 | 3 | 2011-01-01 13:00:00
7 | 2 | 11 | 2011-06-06 11:23:42
(7 rows)
Die innere Abfrage gibt Ihnen Folgendes:
=> select id, rank() over (partition by thread_id order by created_at desc)
from posts
where receiver_id = 1;
id | rank
----+------
3 | 1
2 | 2
1 | 3
6 | 1
4 | 2
5 | 1
(6 rows)
Und dann wickeln wir die äußere Abfrage darum herum, um nur die Top-Ranking-Matches abzuschälen:
=> select id
from (
select id,
rank() over (partition by thread_id order by created_at desc)
from posts
where receiver_id = 1
) as dt
where rank = 1;
id
----
3
6
5
(3 rows)
Fügen Sie also die gewünschten zusätzlichen Spalten hinzu und verpacken Sie alles in einem Post.find_by_sql
und fertig.