Reputation:
I've been thinking about how gmail queries their conversations. I know they are using different technology, but I want to mimic as best I can.
Currently I fetch a list of conversations and then I have to fetch messages for each conversation. I can use a normal join:
Conversation.joins(:messages).first
But that will join every single message, and I only need the last message. How would I structure this query? Even better would be to join when I do Conversation.all:
Conversation.joins(:messages).all # but only join last message for each conversation
Additionally, can I use conditions to join the last message with a certain user id?
message.user_id = 1
Conversation.joins(:messages).all # only last message where user_id = 1
I am using squeel if that helps in demonstrating the query.
What is the most optimal way of fetching conversations, and the last message for each conversation?
Upvotes: 0
Views: 231
Reputation: 906
This is customarily accomplished using a having clause. You might do something like this, in Squeel (note, untested):
user.conversations.includes{messages}.group{id}.having{messages.id == max(messages.id)}
You'll be grouping on the conversation id, then using having to weed out all rows but the one with the max message id in each group.
Note: "having" isn't a particularly desirable thing to do, in many cases. You'll want to check the explain for the query to make sure you're not going to cause yourself undue pain down the road. If so, you might consider adding a cache column on the conversation that points at the last message in the conversation, and then just setting up an association against that column.
Upvotes: 2