Als je het niet erg vindt om je handen vuil te maken met een beetje SQL, kun je een vensterfunctie om de klus te klaren. Je kunt de post-ID's krijgen met deze SQL:
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
Als u meer kolommen wilt, voegt u deze toe aan beide SELECT-clausules. De #{user.id}
is natuurlijk de ontvanger waarin u geïnteresseerd bent.
Het interessante deel is de vensterfunctie:
rank() over (partition by thread_id order by created_at desc)
Dit verdeelt de tabel in groepen op basis van thread_id
(soort van een gelokaliseerde GROUP BY), sorteer ze op tijdstempel (meest recente eerst), en dan rank()
levert 1 op voor het eerste item in elke groep, 2 voor de tweede, enz.
Gegeven een tabel die er als volgt uitziet:
=> 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)
De innerlijke vraag geeft je dit:
=> 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)
En dan wikkelen we de buitenste vraag daar omheen om alleen de toprangschikkingsovereenkomsten af te pellen:
=> 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)
Dus voeg de extra kolommen toe die je wilt en verpak het allemaal in een Post.find_by_sql
en je bent klaar.