MySQL ORDER BY on a thread-based message system - php

I've created a message system where users can send messages to each other. It's thread-based like in Facebook. So every user should be in only one specific message-thread with another single user.
The main overview of all messages isn't working as I want it to be. It only shows the oldest (first) message text and date of a thread and doesn't sort by latest message sent.
The MySQL database structure:
messages_assign: id,uid,thread_id,status,date
messages_content: id,uid,thread_id,text,date
messages_thread: id,creator_uid,receiver_uid
I think it's self-explanatory, but to clarify: messages_assign assigns the content(s) to a specific message thread. I want to expand this message system to be able to send messages to multiple users someday, that's why I came up with this structure.
This is my MySQL query in PHP:
$menu = mysql_query("SELECT
t.`id`, t.`creator_uid`,
c.`uid` AS content_uid, c.`text`, c.`date` AS content_date,
a.`status`, a.`date` AS assign_date,
CASE
WHEN t.`creator_uid`='".sInput($_SESSION['uid'])."' THEN `receiver_uid`
WHEN t.`receiver_uid`='".sInput($_SESSION['uid'])."' THEN `creator_uid`
END AS uid
FROM `messages_content` c
LEFT JOIN `messages_thread` t ON t.`id` = c.`thread_id`
LEFT JOIN `messages_assign` a ON a.`id` = t.`id`
WHERE
t.`creator_uid`='".sInput($_SESSION['uid'])."'
OR
t.`receiver_uid`='".sInput($_SESSION['uid'])."'
GROUP BY t.`id`
ORDER BY c.`id` DESC") or die (mysql_error());
I guess that there has to be a sub-query somewhere to let it sort by the latest date and text, but I'm not familiar with that and also wouldn't know where to put that and how?
So basically I just want that the message threads are sorted by the latest message received, showing the latest text and date of a specific thread.

Related

Reorder chat tabs so tabs with newest received or sent messages are on top of list

I'm working on a simple messenger.
This is how the Chat table looks like:
This is how the User table looks like:
This is how the PinnedUser table looks like:
By using this query I can display chat tabs with users I have pinned (pinned to the Messenger so I can chat with them).
SELECT pu.*, u.* FROM User u JOIN PinnedUser pu ON pu.pinned_user = u.user_id
WHERE pu.pinned_by_user = $actual_user ORDER BY u.first_name ASC
Example of chat tabs:
When I click on one of those tabs, chat messages with that user are displayed.
Right now the tabs are ordered by users first name (you can see that in the query above). What I need to somehow do is, that I need to order tabs by newest messages.
So if "Anet" sends me a message (and I refresh the page because right now I don't wanna do it with AJAX), that tab will appear on the top of the tab list. Then if "Demo" sends me a message (and I refresh the page because right now I don't wanna do it with AJAX), "Demo" tab will be positioned on the top and "Anet" will be right below him. So I need the tabs to be ordered by "newest received or sent messages" just like Facebook has it in its messenger.
I tried to do the magic with GROUP BY but I failed.
You need to retrieve the date of the latest received message from each user - for this, we need to look up table chat. You can either join, or use a correlated subquery directly in the where clause:
select pu.*, u.*
from user u
join pinneduser pu on pu.pinned_user = u.user_id
where u.user_id = ?
order by (
select coalesce(max(send_at), '200-01-01')
from chat c
where c.sender_id = pu.pinned_user_id and c.receiver_id = u.user_id
) desc
coalesce() is there in case there are no messages to be found, in which case the pinned user should be sorted last (this assumes that you don't have messages before year 2k).
You might want to retrieve the message date as well, to display it in your application or else (in which case we don't need a default value):
select
pu.*,
u.*,
(
select max(send_at)
from chat c
where c.sender_id = pu.pinned_user_id and c.receiver_id = u.user_id
) latest_message_sent_at
from user u
join pinneduser pu on pu.pinned_user = u.user_id
where u.user_id = ?
order by (latest_message_sent_at is null), latest_message_sent_at desc

Activity feed (like FB timeline): What is the logic to obtain the latest actions in the database?

In my application, there are 10-20 various kinds of actions that I want to display in activity feed:
users sign up, become friends with each other and follow each other
users register objects, buy and sell objects, follow objects
users register sets of objects and add objects to the sets of objects.
Everything is being stored in a mysql database.
How do I obtain the latest actions/events and display them in an activity feed?
In my android app I have a ListView for the activity feed and an ENUM object describing those different kinds of actions, so the list view can be fed different sets of events and display different layouts for each event, but I dont know how to get the latest actions in the database in order to feed the activity.
What I was thinking of doing is to insert an ENUM EVENT in an EVENTS table in mysql each time a subject gets added, each time a user registers, or a user does something and then get the latest 10 events from that table and send it to the app, but how do I link certain event from that table to something happening in the database?
I have never learned how to create an activity and Im improvising but I dont know whether Im on the right path and if I am, how to implement that logic.
PS: I have an extremely basic undestanding of MySQL, so be gentle :)
I assume you have a user table, and that you have an event table and a table that links the user to the event so try
SELECT (*|[columns you want])
FROM events E
INNER JOIN events_users EU
ON EU.event_id = E.id
INNER JOIN users U
ON EU.event_id = U.id
ORDER BY EU.(timestamp) DESC LIMIT 30
And without aliasing
SELECT (*|[columns you want])
FROM events
INNER JOIN events_users
ON events_users.event_id = events.id
INNER JOIN users
ON events_users.event_id = users.id
ORDER BY events_users.(timestamp) DESC LIMIT 30
Bare minimum
user (id)
events_users (user_id, event_id, timestamp)
event(id)
In your event table define a type field which corresponds to each activity types such as
type 1: user registration
type 2: add comment
etc..
Then you can have a field in your table that store the current time the entry got created/updated such as UpdateTime. Whenever you are creating or updating an entry, update the UpdateTime field with current time. Then while fetching result do a ORDER BY UpdateTime DESC with limit.
SELECT id, userid, name, type, activity ,updateTime
FROM users usr INNER JOIN events ev
ON ev.user = usr.userid
WHERE updateTime > 0
ORDER BY updateTime LIMIT 0,10;
SQLFIDDLE
A good tutorial for MySQL beginner is w3school

how to group reply messages to original message

I am storing replies in a separate table with the original message as the reference id. What I'm trying to do is when a message is clicked it grabs all the corresponding replies and displays them under the main message but how to get the corresponding messages?
This is what I've tried but can't find a WHERE clause that works. Is there any way to group these by the to_id and from_id and reference_id or am I on the wrong track all together?
Basic SQL is pretty much my ceiling at this point so any pointer appreciated.
replies table
MESSAGE TABLE
What I want to do is to have one main conversation with someone and if you message them once all further replies and/or new messages appear underneath
EXAMPLE:
MAIN MESSAGE to USER 1
//grouped by date and if a certain period passes block with a line
reply from user 2
reply from user 1
----------------------------
days later
new message from user 2
so on...
Not sure if this is what you are looking for
SELECT m.subject, r.Message, r.from_id, r.to_id FROM MESSAGE m
JOIN replies r on m.reply_id = r.id
WHERE ((m.from_id = `user_1_id` AND m.to_id = `user_2_id`)
OR (m.from_id = `user_2_id` AND m.to_id = `user_1_id`))
ORDER BY r.date_sent asc
Are you looking for something like this? If you can provide the layout of both the messages and replies tables it may help...
SELECT
`messages`.`message`,
`replies`.`reply`
FROM
`messages`
JOIN
`replies` ON(`messages`.`id` = `replies`.`message_id`)

Trying to display #mentions for a user but my query is spitting out an error

I'm trying to display #mentions for my currently logged in user but I'm getting a syntax error and I don't know what it is. My database is mysql and my query currently looks like this:
$sql = "SELECT
users.username,
posts.post,
posts.time_stamp,
FROM users
INNER JOIN posts
ON users.id = posts.user_id
INNER JOIN mentions
ON users.id = mentions.user_id
WHERE mentions.user_id = '$userid'
AND mentions.unread = 1
ORDER BY time_stamp DESC
";
What I want to happen is for the currently logged in user to go to a page called "mentions" and to get a list of the posts they were mentioned in and the username who mentioned them BUT ONLY if the mention is unread (i.e. is equal to 1) because later on that same page I will then change the displayed mentions 'unread' status to 0, which means it has been read.
I hope this makes sense! If you need more info on the db structure etc, shoot a comment and I will give you more info.
You have at least one syntax error in this line:
posts.time_stamp,
Remove the comma. It is not needed before from.

SQL for displaying and sorting messages and their replies in one table

I have written a simple messaging system for a CMS I am developing and am having a hard time finding the best way to grab all the messages and their replies ordered by the newest (message or reply).
I have a table called "messages" that has the fields:
*id, active[1,0], subject, message, datetime, user_from, user_to, reply_id*
It's all straight forward and the *reply_id* is empty for main level messages and contains the parent id for replies. I am at a loss for how to write the SQL to grab all the main level messages in datetime DESC order based on themselves AND their replies. I'm sure it's done with a UNION of some sort but my SQL skills are lacking. And if the same SELECT can give a count of the replies within each main level message that would be amazing!
Any help would be greatly appreciated!
It's late and I'm tired but I think you could try something like that:
SELECT main.*, COUNT(reply.id) AS cnt_replies, MAX(reply.datetime) AS max_datetime
FROM posts AS main
LEFT JOIN posts AS reply
ON main.id = reply.reply_id
GROUP BY main.id
HAVING main.reply_id IS NULL
ORDER BY max_datetime DESC
EDIT: fixed query
EDIT2: now includes messages without any replies

Categories