简体   繁体   English

私人聊天系统-获取每次聊天的最新消息

[英]Private chat system - get last message of each chat

I am making a chat system between 2 users. 我正在建立2位用户之间的聊天系统。 I have chat table that looks like that: (Here is the schema: SQL Fiddle ) 我有一个看起来像这样的聊天表:(以下是架构: SQL Fiddle

        --------------------------------------------------------------------------------
        | message_id | sender_id | receiver_id  | message_text  |       date           |
        --------------------------------------------------------------------------------
        |     1      |     20    |      100     |  Hello mate   |  2018-04-29 12:15:33 | 
        --------------------------------------------------------------------------------
        |     2      |    100    |      20      |   Hi there    |  2018-04-29 13:20:05 | 
        --------------------------------------------------------------------------------
        |     3      |     13    |      44      |   Alright     |  2018-04-29 14:35:15 | 
        --------------------------------------------------------------------------------
        |     4      |     20    |      57      |   Hi user 57  |  2018-04-29 16:44:34 | 
        --------------------------------------------------------------------------------

I want to get the rows of the last messages from each chat a user is engaged in, so in the above example, user 20 should get 2 rows: row of message_id 2 (Because he is engaged in a chat with user 100, although he did not send the last message), and row of message_id 4 (because he sent message to user 57) It's basically like WhatsApp where you always have the first messages of any chat at the top. 我想从用户进行的每次聊天中获取最后一条消息的行,因此在上面的示例中,用户20应该获得2行:message_id 2行(因为他正在与用户100进行聊天,尽管他没有发送最后一条消息)和message_id 4行(因为他向用户57发送了消息)基本上就像WhatsApp一样,您始终在顶部拥有任何聊天的第一条消息。

The problem is I can only get the last message if the user is the SENDER and not if he is the receiver: 问题是,如果用户是SENDER,则我只能得到最后一条消息,而如果他是接收者,则不能:

 SELECT * FROM chat 
 WHERE message_id IN 
(SELECT MAX(message_id) FROM chat WHERE sender_id=:sender_id 
 GROUP BY receiver_id) ORDER BY date DESC

I think I should add another column "chat_id" which would be a number that is identical for each 2 users that are in the same chat (so user 100 and 20 will have same chat_id whether they are the senders or receivers, and users 13 and 44 will have a different in this example), 我想我应该添加另一列“ chat_id”,该列对于在同一聊天中的每个2个用户来说都是相同的(因此,无论用户100和20是发送者还是接收者,用户100和20都将具有相同的chat_id,用户13和在此示例中,44将有所不同),

Or, there is a better option? 还是有更好的选择?

You could use an union between sender and receiver for get a result for both 您可以在发送者和接收者之间使用联合以获得两者的结果

  You could use 
  select * 
  from chat 
  inner join  (
    select max(message_id) max_id, user from (
    select message_id, sender_id as  user
    from chat
    union 
    select message_id, receiver_id 
    from chat) t 
    ) t1 on t1.max_id = chat.message_id
          and chat.sender_id=:sender_id 

To handle this efficiently, start with these two queries: 为了有效处理此问题,请从以下两个查询开始:

select message_id, sender_id as other_id
from messages
where receiver_id = :user
order by message_id desc;

select message_id, receiver_id as other_id
from messages
where sender_id = :user
order by message_id desc;

These can each be optimized using two indexes: messages(receiver_id, sender_id, message_id) and messages(sender_id, receiver_id, message_id) . 可以使用两个索引来优化它们: messages(receiver_id, sender_id, message_id)messages(sender_id, receiver_id, message_id)

You can union all them together and sort or aggregate to get the maximum value: 您可以union all它们结合在一起,进行排序或汇总以获得最大值:

select m.*
from messages m
where m.message_id in (select max(message_id)
                       from ((select message_id, sender_id as other_id
                              from messages
                              where receiver_id = :user
                              order by message_id desc
                              limit 1
                             ) union all   
                             (select message_id, receiver_id as other_id
                              from messages
                              where sender_id = :user
                              order by message_id desc
                              limit 1
                             )
                            ) mm
                      );

The subqueries should be able to make use of the indexes (actually, the "other id" is not needed). 子查询应该能够利用索引(实际上,不需要“其他ID”)。 The max() is then on two rows, and the in should be able to take advantage of an index on (message_id) . 然后, max()在两行上,并且in应该能够利用(message_id)上的索引。

EDIT: 编辑:

For the revised problem, I can't think right of hand of a really efficient method. 对于修改后的问题,我想不出一种真正有效的方法。 Here is one method: 这是一种方法:

select m.*
from messages m
where m.message_id in (select max(m2.message_id)
                       from messages m2
                       where :user in (sender_id, receiver_id)
                       group by (case when sender_id = :user then receiver_id else sender_id end)
                      );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM