Reading data from table using LIMIT while the order changes - mysql

Okay, let me explain.
You know how Facebook Messenger and Discord both have the last messaged friends list? It is a list of all of your friends order by whoever texted you last. Now, if you had over 100 people in that list, it would be better to send the list to the client in chunks of 10. Once the client reaches the bottom, it asks for the next 10. This can be done with the LIMIT offset, amount.
But now, the problem. The user might open the messenger, talk to someone for 10 minutes, and then scroll further down in the last messaged friends list. In this case, the table has changed before the user has retrieved the full list. The list in database is now in a different order because someone messaged them in the meanwhile and is now on top of the list, but the client already has the first chunk of the list, but this doesn't contain the people that texted them.
In case my explanation was not enough, here's a visual demonstration:
Visual demo
'Last messaged friends' list in database (ordered by latest timestamp):
Person 23
Person 77
Person 93
Person 99
Person 67
Person 85
User connects, asks for the first 3 entries.
Client now has (ordered by latest timestamp):
Person 23
Person 77
Person 93
'Person 99' messages that user. 'Person 99' is now on top of the list.
'Last messaged friends' list in database (ordered by latest timestamp):
Person 99
Person 23
Person 77
Person 93
Person 67
Person 85
User scrolls down. Client asks for the next 3 entries.
Client now has (ordered by latest timestamp):
Person 23
Person 77
Person 93
Person 93 (duplicate)
Person 67
Person 85
('Person 99' missing)
Is this something I could fix/implement with a more advanced SQL query?
If I can't, how could I implement this in other ways?
For information, I have a Socket.io (a.k.a more advanced WebSocket) connection between the server and the client, I can send whatever necessary information thru that.

It sounds like you want aggregation to avoid duplicates:
select person_id
from messages
group by person_id
order by max(timestamp) desc;

Thank you, Hector Vido, for the suggestion. (he made a comment right below my question, go upvote)
"Selecting messages by timestamp don't solve this? You keep the last timestamp and then ask by anoter 10 registries >= that timestamp"
Solution
I'll keep the oldest and newest timestamp in the client side.
If the client scrolls down, I will request 10 entries before the oldestTimestamp and then the new oldestTimestamp will be the oldest timestamp of the received entries.
Also after every 10 seconds, I could request for entries after the newestTimestamp and then the new newestTimestamp will be the newest timestamp of the received entries.

Related

mySQL Messaging Between Two Users

I have a private messaging system that uses a mysql database.
Messages are passed between two users.
However, when any user deletes the conversation history, it should not be deleted in the other user.
I could create an Additional column called "deleted_users" and use LIKE when listing messages.
But I'm worried about performance and I need your help.
id
user_from
user_to
msg
1
82
85
test
2
85
82
test

Reliable and accurate threading structure for emails?

I'm working on a email project. I would like to display email in threads just like gmail.
What is the best approach to display mails in thread?
I have checked jwz threading algorithm. But looks like that algorithm is written for projects that has no databases.That algorithm focuses on these three header keys. Message-ID, In-Reply-To and References
Can someone tell me what is the proper, efficient and most accurate way to achieve threading using mysql database.?
Do I have to use separate table for threads and references?
If possible give me some sample mysql queries. So I can understand better.
Thank you.
Any message board design eg wordpress etc should also works for email. I also come up with a design:
email.id user_id subject status folder created updated ...other info you'd save
1 123 Hello New Inbox Y-m-d.. Y-m-d.. ...
2 3456 World Replied Inbox ...
reply.id email_id reply_to_id user_id created email_txt ip ...
10 1 0 890 Y-m-d.. Hi ...
20 2 0 5678 ...
30 2 20 3456 ... Replyto 2
55 2 30 5678 .... Replyto 3
So in your email.folder.index page:
SELECT * FROM email WHERE user_id = 12345 ORDER BY updated desc LIMIT 50
And when you click one an email on index page, goto email details page:
SELECT * FROM reply WHERE email_id = 2 ORDER BY created, reply_to_id
The key magic is that the tree is built based on reply_to_id

How to build a compound WHERE clause that is limited to the current record

I have an (example) application that sends baseball scores to users. The use is able to select which inning the score should be sent for some specific teams (e.g. 'Send me Yankee scores after 7 innings). There is also a setting for 'All other' teams (e.g. 'Send me scores for any other teams after 8 innings).
These settings are saved to a table which stores the user, a team ID, and the number of innings. Team ID '99' is used for 'All other teams'. So our user's records would look like:
**User - Team - Innings**
Bob - 13 (Yankees) - 7
Bob - 99 (all other teams) - 8
Now it comes time to check the scores and send some notifications. I find that the Yankees game has reached the end of the 7th inning and fire off a message to Bob.
20 minutes later, that same Yankees game has reached the 8th inning. Bob should NOT receive a message this time, since he got one after 7 innings.
Now consider Julie:
**User - Team - Innings**
Julie - 13 (Yankees) - 8
Julie - 99 (all other teams) - 7
Julie has used the settings to say 'send me all scores after 7 innings, except for Yankees scores which should wait until 8 innings'. This time, after 7 innings in the Yankees game, Julie should NOT receive a notification.
Finally, Dirk. Dirk is a little confused:
**User - Team - Innings**
Dirk - 13 (Yankees) - 7
Dirk - 99 (all other teams) - 7
His Yankees setting is pretty redundant, but whatever - as long as he doesn't receive the same notification twice, he's fine.
The Yankees game has just completed the 7th inning. What is the best way to query my table and decide who needs to get alerts?
I am fairly new to SQL, but I think I can make a plain-language representation:
Send alerts to:
Any people that care about the team A team after X innings, unless
they also care about ALL teams after < X innings (they would already
have received an alert)
PLUS
Any people that care about ALL teams
after X innings, unless they also care about team A after < X innings
(they would already have received an alert)
(I don't think this actually covers Dirk's scenario though?)
My best guess is that I need to make a WHERE clause that matches the team AND the innings, but then also tests if there is a record in the same table for the same user that meets the criteria above.
This is way beyond me - I don't even know what techniques to google. I couldn't even come up with a decent question title :/
Start by making a select that shows specific team settings plus general team settings. You can do that by joining the table on itself.
select s.*, g.innings as g_innings
from settings s join settings g
on (g.user = s.user and g.team = 99) -- 'g.team is null' would be better, yes...
The rest is easy: use this select twice with appropriate where clauses, and union the result.
EDIT: use a single query and OR the two where clauses.
select s.*, g.innings as g_innings
from settings s join settings g
on (g.user = s.user and g.team = 99) -- 'g.team is null' would be better, yes...
where (s.innings = X AND g.innings >= X)
OR (g.innings = X AND s.innings >= x)

Get messages in a given trail

The following is a simplified table structure showing messages belonging to a single mail trail. i.e. the trail started with messageID 46 (where parentMessageID = 0). Message 47 is a reply to message 46. Message 89 is a reply to message 47.
tblMessages
messageID parentMessageID
-----------------------------
46 0
47 46
89 47
The table would obviously have thousands of message records.
How would you query the table to get all messages in a particular trail, e.g. the trail shown above?
Wouldn't it be better to store a conversation identifier?
The problem you're going to have is that you have no indication of the depth level, and so trying to loop over is almost impossible. It would be more logical to set the parentMessageID to the very root (i.e. where its parentMessageID == 0), and then order them by date.

How can I write a SQL query with multiple COUNTs for different GROUP BYs?

One of my coworkers is working on a SQL query. After several joins (workers to accounts to tasks), she's got some information sort of like this:
Worker Account Date Task_completed
Bob Smith 12345 01/01/2010 Received
Bob Smith 12345 01/01/2010 Received
Bob Smith 12345 01/01/2010 Processed
Sue Jones 23456 01/01/2010 Received
...
Ultimately what she wants is something like this - for each date, for each account, how many tasks did each worker complete for that account?
Worker Account Date Received_count Processed_count
Bob Smith 12345 01/01/2010 2 1
... and there are several other statuses to count.
Getting one of these counts is pretty easy:
SELECT
COUNT(Task_completed)
FROM
(the subselect)
WHERE
Task_completed = 'Received'
GROUP BY
worker, account, date
But I'm not sure the best way to get them all. Essentially we want multiple COUNTs using different GROUP BYs. The best thing I can figure out is to copy and paste the subquery several times, change the WHERE to "Processed", etc, and join all those together, selecting just the count from each one.
Is there a more obvious way to do this?
SELECT worker, account, date,
SUM(task_completed = 'Received') AS received_count,
SUM(task_completed = 'Processed') AS processed_count
FROM mytable
GROUP BY
worker, account, date