简体   繁体   English

codeigniter仅加入最新行

[英]codeigniter join only most recent row

I am making a dating app similar to tindler, where users can like or dislike each other. 我正在制作类似于Tindler的约会应用程序,用户可以互相喜欢或不喜欢。 If two users both like each other, they should be able to chat with each other. 如果两个用户彼此喜欢,则他们应该能够彼此聊天。 I have come up with the following query to handle pulling a list of users you can chat/have chats with already - the problem i'm having is i only want to pull the most recent chat message, solely to display a little blurb before you click into the chat itself. 我想出了以下查询来处理您可以聊天/已与之聊天的用户的列表-我遇到的问题是我只想提取最新的聊天消息,只是为了在您之前显示一些内容点击进入聊天本身。 My query works, but it returns the oldest (lowest ID) chat record, instead of the newest. 我的查询有效,但是它返回最旧的(最低ID)聊天记录,而不是最新的。 Order by does not seem to have an impact on returning the correct result. Order by似乎对返回正确结果没有影响。

$data = $this->db->select('users.id,display_name,city,state,gender,users_pictures.picture,users_chats.message')
                ->join('users_pictures','users_pictures.user_id=users.id')
                ->join('users_chats','users_chats.user_id=users.id OR users_chats.foreign_user_id=users.id','left outer')
                ->where('EXISTS (SELECT 1 FROM users_likes_dislikes ld WHERE (ld.foreign_user_id = '.$this->user_id.' AND ld.user_id=users.id AND ld.event_type=1) OR (SELECT 1 FROM users_likes_dislikes ld WHERE ld.foreign_user_id = users.id AND ld.user_id='.$this->user_id.' AND ld.event_type=1))', '', FALSE)
                ->where('NOT EXISTS (SELECT 1 FROM users_blocks ub WHERE (ub.foreign_user_id = users.id AND ub.user_id='.$this->user_id.') OR (SELECT 1 FROM users_blocks ub WHERE ub.foreign_user_id = '.$this->user_id.' AND ub.user_id=users.id))', '', FALSE)
                ->where('((users_chats.user_id='.$this->user_id.' OR users_chats.foreign_user_id='.$this->user_id.') OR (users_chats.user_id is NULL AND users_chats.foreign_user_id is NULL))')
                ->order_by('users_chats.id','DESC')
                ->group_by('users.id')              
                ->get('users')
                ->result_array();

Here is the current mysql table for users_chats: 这是users_chats的当前mysql表:

id user_id foreign_user_id message created
1 1 4 test 2013-05-22 15:42:44
2 1 4 test2 2013-05-22 15:44:38

I assumed the order_by would ensure that the test2 message is what displayed. 我假设order_by将确保显示test2消息。

Here is sample output: 这是示例输出:

Array ( [0] => Array ( [id] => 4 [display_name] => testinguser [city] => west hills [state] => ca [gender] => 2 [picture] => testasdfasdf.jpg [message] => test ) )

Any help is much appreciated :) 任何帮助深表感谢 :)

edit - the query itself (without group by, this works but i need it to group to the user.id so that i don't have multiple entries for the same user in the array): 编辑-查询本身(没有分组依据,这有效,但我需要将其分组到user.id,以便我在数组中没有针对同一用户的多个条目):

SELECT
  `users`.`id`,
  `display_name`,
  `city`,
  `state`,
  `gender`,
  `users_pictures`.`picture`,
  `users_chats`.`message`
FROM (`users`)
  JOIN `users_pictures`
    ON `users_pictures`.`user_id` = `users`.`id`
  JOIN `users_chats`
    ON `users_chats`.`user_id` = `users`.`id`
       OR users_chats.foreign_user_id = users.id
WHERE EXISTS(SELECT
           1
         FROM users_likes_dislikes ld
         WHERE (ld.foreign_user_id = 1
            AND ld.user_id = users.id
            AND ld.event_type = 1)
          OR (SELECT
            1
              FROM users_likes_dislikes ld
              WHERE ld.foreign_user_id = users.id
              AND ld.user_id = 1
              AND ld.event_type = 1))
    AND NOT EXISTS(SELECT
             1
           FROM users_blocks ub
           WHERE (ub.foreign_user_id = users.id
              AND ub.user_id = 1)
            OR (SELECT
                  1
                FROM users_blocks ub
                WHERE ub.foreign_user_id = 1
                AND ub.user_id = users.id))
    AND ((users_chats.user_id = 1
       OR users_chats.foreign_user_id = 1)
      OR (users_chats.user_id is NULL
          AND users_chats.foreign_user_id is NULL))
ORDER BY `users_chats`.`created` DESC

Your group by clause could be the culprit here. 您的group by子句可能是这里的罪魁祸首。 I believe that the grouping operation happens first, leaving you with your first result. 我相信分组操作会首先发生,让您拥有第一结果。 Rather than selecting all these rows (when there's tons it'll take longer), you should specify how many you want - it looks to me like that isn't too far out of the picture here, anyways. 而不是选择所有这些行(当有很多吨时,它会花费更长的时间),您应该指定想要的行数-在我看来,无论如何,这都不算太远。 Specify how many you want, get rid of the group by clause, and you should order by date since you HAVE a date column. 指定想要的数量,摆脱group by子句,并且由于您具有日期列,因此应按日期排序。 Does that help? 有帮助吗?

I'm not sure how to do it with your db Abstraction, but the query you want is 我不确定如何使用db Abstraction进行操作,但是所需的查询是

SELECT
   `users`.`id`,
   `display_name`,
   `city`,
   `state`,
   `gender`,
   `users_pictures`.`picture`,
   chats1.`message`
  FROM (`users`)
    JOIN `users_pictures`
      ON `users_pictures`.`user_id` = `users`.`id`
    JOIN `users_chats` AS chats1
      ON (chats1.`user_id` = `users`.`id`
         OR chats1.foreign_user_id = users.id)

Here comes the important part 重要的部分到了

         AND NOT EXISTS(
           SELECT *
             FROM users_chats AS chats2
             WHERE ((chats2.user_id = chats1.user_id AND chats2.foreign_user_id = chats1.foreign_user_id)
               OR (chats2.user_id = chats1.foreign_user_id AND chats1.user_id = chats2.foreign_user_id))
               AND chats2.created_date > chats1.created_date --which I assume is a time stamp
           )

It's not pretty, I know. 我知道这不漂亮。

  WHERE EXISTS(SELECT 1
    FROM users_likes_dislikes ld
      WHERE (ld.foreign_user_id = 1
        AND ld.user_id = users.id
        AND ld.event_type = 1)
        OR (SELECT 1
          FROM users_likes_dislikes ld
          WHERE ld.foreign_user_id = users.id
          AND ld.user_id = 1
          AND ld.event_type = 1)
    )
    AND NOT EXISTS(SELECT 1
       FROM users_blocks ub
       WHERE (ub.foreign_user_id = users.id
          AND ub.user_id = 1)
        OR (SELECT
              1
            FROM users_blocks ub
            WHERE ub.foreign_user_id = 1
            AND ub.user_id = users.id)
    )
    AND ((chats1.user_id = 1
        OR chats1.foreign_user_id = 1)
      OR (chats1.user_id is NULL
        AND chats1.foreign_user_id is NULL))
  ORDER BY `users_chats`.`created` DESC

Basically, only successfully join if there's no more recent message. 基本上,只有在没有其他最新消息时才成功加入。 There are some better native solutions - TSQL (Microsoft SQL Server) has CROSS APPLY, which would be great here - but without knowing more about your DB layer, I can't be sure. 有一些更好的本机解决方案-TSQL(Microsoft SQL Server)具有CROSS APPLY,在这里会很好-但在不了解您的数据库层的情况下,我不确定。 You may want to considered re-architecting your chat structure: 您可能需要考虑重新构建聊天结构:

Users(int id /*also other user info*/)
chats(int id, datetime date_initiated, bool /*or bit, or short int*/ is_active)
chat_users (int chat_id, int user_id)
chat_messages (int chat_id, int user_id /*author*/, datetime date_sent, varchar(n) message)

With a structure like that, you could get all your most recent messages like this: 使用这样的结构,您可以获取所有如下的最新消息:

SELECT *
  FROM Users AS u
    INNER JOIN chat_users AS cu
      ON u.id = cu.user_id
    INNER JOIN chats AS c
      ON c.id = cu.chat_id
        AND c.is_active = 1
    INNER JOIN chat_messages AS m
      ON m.chat_id = c.id
        AND NOT EXISTS (
          SELECT 1
            FROM chat_messages AS m2
              WHERE m2.chat_id = m.chat_id
                AND m.date_sent < m2.date_sent
        )
     INNER JOIN Users as sender
       ON m.user_id = sender.id
  WHERE u.id = ###
  ORDER BY m.date_sent DESC

You could even create a "Chat most recent message" view like: 您甚至可以创建“聊天最近的消息”视图,例如:

CREATE VIEW Chat_Recent AS
  SELECT * /* WHATEVER YOU LIKE */ 
    FROM chats AS c
      INNER JOIN chat_messages AS m
        ON m.chat_id = c.id
          AND NOT EXISTS (
            SELECT 1
              FROM chat_messages AS m2
                WHERE m2.chat_id = m.chat_id
                  AND m.date_sent < m2.date_sent
          )
       INNER JOIN Users as sender
         ON m.user_id = sender.id

Try MySQL MAX(): 试试MySQL MAX():

$this->db->join('(SELECT MAX(message) AS lastMsg FROM users_chats WHERE users_chats.user_id=users.id OR users_chats.foreign_user_id=users.id GROUP BY users.id)', 'left outer');

Then add the "lastMsg" on your select. 然后在您的选择上添加“ lastMsg”。

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

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