PHP/MYSQL - showing newest distinct value from multiple columns - mysql

This is my mysql table structure:
msgid | senderid | sender | recipientid | recipient | title | message | date
I'm looking to present in inbox for my private messaging system as Facebook have done. That is, each conversation is output ONE TIME from the table irrespective of whether it is incoming or outgoing. For example:
My username is 'admin'.
USER | MESSAGE | DATE | DIRECTION
Dan | Hello | 1/2/10 | Incoming
Bob | How are you Bob?| 30/1/10 | Outgoing
The problem is not repeating the username because of differing directions. For example:
USER | MESSAGE | DATE | DIRECTION
Dan | Hello | 1/2/10 | Incoming
Bob | How are you Bob?| 30/1/10 | Outgoing
Bob | Hi admin | 30/1/10 | Incoming
So I need to make sure that the only message that shows is the newest communication irrespective of the direction (i.e., the newest message with another user, irrespective of whether that user is the 'sender' or 'recipient').
I'm using PHP/MYSQL for this website. I've tried thousands of ways to do this but I just can't figure it out. It might be that my database is incorrectly structured. I will be online for a few hours (and will continually check after that) so feel free to ask any questions.

If I understand correctly this should do what you need:
SELECT
IF(senderid = :userId,recipient,sender) AS USER,
message,
date,
IF(senderid = :userId,'Outgoing','Incoming') AS DIRECTION
FROM message
WHERE senderid = :userId OR recipientid = :userId
ORDER BY date DESC
The USER and DIRECTION is determined based on whether this user is the sender or not.
If you are only interested in the latest message you can add a LIMIT to this query.

I have somewhat solved my own question with the following:
SELECT * FROM (
SELECT * FROM (
(SELECT id, reciever, recieverid, message, datetime FROM messages WHERE sender = '$user')
UNION
(SELECT id, sender, senderid, message, datetime FROM messages WHERE reciever = '$user')
) as t
ORDER BY datetime DESC
) as t2
GROUP BY reciever ORDER BY datetime DESC
It seems to do the trick, although I don't know which messages are incoming or outgoing. I'll know if it works properly when I have a chance to invite some actual users.

Related

How to store unread messages count for group chat in Laravel app

I have read all the answers but still i did not get the answer which i am looking for. Here let me explain what i have and i have done so far.
I have created a chat application where user can have duo chat or a group chat. i have following database structure:
chatrooms
id | creator_id (who created chatroom) | type (duo/group) | group_id (if chatroom type is 'group')
messages
id | chatroom_id | senders_id | recipient_id | message | read(by default 0)
I have one more table to keep track of chatroom participants
chatroom_user
id | chatroom_id | user_id
Now everything is working fine for duo type chats.
I am getting unread messages count for duo chat by running this query :
return auth()->user()
->chatrooms()
->withCount(['messages' => function (Builder $query) {
$query->where('read', 0)->where('recipient_id', auth()->user()->id);
}])
->get();
And this works perfectly fine:)
But now if i have group chat i have multiple recipients. i am not able to do what i have done above. So i created one more pivot table
message_recipient
id | message_id | recipient_id | read
Now this way i can keep track of unread messages for specific user. But the problem is when i save a message i need to add here so many rows how many recipients are and that for each message.
suppose i have a group with 10 people if somebody send message 'hello' i need to put 10 records in this table ( actually 10-1 ).
So my question is: will it be a performance issue?
Is there any better way to handle this kind of situation ?

MySQL: Get latest unread message from 3 or 4 tables that are associated with eachother

Thank you for your help! I'm pretty new to SQL. And thank you for bearing with me through this long explanation. Just want to make sure I'm detailed:
I'm building a messaging system. What I need to do is retrieve the latest unread messages for 1 or more specified users, in DESC order.
Here is how I have the system currently structured:
A conversation can be created between 2 or more users and/or groups, and each user and/or group is associated to that conversation. Users/groups in the conversation can send messages to each other.
When a message is sent, it is associated to the conversation. Then each user/group in the conversation is associated to that new message.
So to store all of this, I have the following tables:
conversation
message
assoc_message__conversation
assoc_user_group__conversation
assoc_user_group__message
I have the following db-fiddle with my table structure and example data inserted into them:
https://www.db-fiddle.com/f/s5bU15eVSxb5TDXy2GVtUS/0
As you can see, I've put in 4 conversations, each with 2 messages - "First Message" and "Last Message".
Pretend I'm user u-1000001 and group g-1000001. You can see that this user and group are in conversations 1, 2 and 3 together. You can also see that this user and group have read both messages in conversation 1 by looking in the assoc_user_group__message table.
What I need to do, is to be able to specify u-1000001 and/or g-1000001, and retrieve the latest unread message for each conversation the specified user and/or group is in, ordered by latest unread message DESC (by message_id, not send_datetime). I also need to be able to specify a message_id to retrieve X amount of unread messages before the first request, or X amount of new unread messages after the first request (message_id < 4 or message_id > 4).
I need to retrieve the following fields for each unread message: conversation_id, message_id, message, send_datetime, raw_id, user_type. You can see that these fields are across 4 different tables: message, assoc_user_group__message, assoc_user_group__conversation, assoc_message__conversation
The following is an example of what should be retrieved if I put in u-1000001 and g-1000001 (omitting field send_datetime):
| conversation_id | message_id | message | raw_id | user_type |
-----------------------------------------------------------------
| 3 | 6 | Last Msg | 1000001 | user |
-----------------------------------------------------------------
| 2 | 4 | Last Msg | 1000001 | group |
-----------------------------------------------------------------
| 2 | 4 | Last Msg | 1000001 | user |
-----------------------------------------------------------------
And if I were to just put in u-1000001, I would get the same results, just without the group rows. You can see that conversation_id 1 is omitted because both user and group have read the messages in that conversation.
I know this is a complicated question, but I really appreciate your time and help!

Need database structure for private, group and public chat - MySQL

My basic idea is to build a web-based chat application. I have checked a lot of database structures over the internet for my requirements and the conclusion is that there are so many solutions for that.
So here is the database structure I thought (But I'm pretty sure that it is not 100% correct or at least it can be improved)
Table users:
id | username | email | created_at | updated_at
Table chat_rooms
id | room_type | created_at | updated_at
Table: room_members
id | room_id | user_ids (in serialized form)
Table: messages
id | room_id | sender_id | message | created_at | updated_at
Table: receivers
id | message_id | receiver_id | read_at
There are 3 types of chats:
i) Private chat - a chat between two users
A user will select another user to start to chat with him/her
ii) Group chat - a chat between group of users
A user will add other users into the room to start a group chat
iii) Public chat - a chat between all the users
An open chat room to which anyone can join and send messages
So here is how it will work:
I logged into the site, redirected to the dashboard page. On that page, I have 3 options to start a chat as described above.
Notes:
1) If there is a previous chat between the users it should be shown as soon as I start a chat (pretty similar to Facebook) - This applies to all the three types of chats
2) I want to have a feature which says that when a specific user read a message.
3) I want to keep it scalable as much as possible for the future enhancement
Thanks
Yes this DB structure is workable for make alpha version.
you can make some small changes according to your requirement.

mysql error : "subquery returns more than one row" but i need more than one row from subquery

I have two tables in my problem, one is the USER table with all details of user and a REQUEST table with friend requests from all users to all users. I want to list all the friends of one user who logs into my application.
The USER table attributes are,
id | uname | passwd | fname | e mail | dob | mobileno | habbits | tastes | profession | image
11 | nagaraj | ***** | naga | ng#gml | 3/94 | 998345 | singing | sports | teacher
12 | chiraag | ******* | chiru | ch#gml | 2/93 | 894617 | writing | music | student
Similarly, the REQUEST table attributes are,
rqstTO | rqstFM | fname | e mail | mobile | status
chirag | nagaraj | nagaraj | ng#gml | 99821 | accepted
The tables look like this. Now I want to display the details of the friends( from USER table), only those friends who have accepted the request from the user who logged in. Output may be multiple users. The conditions to be satisfied are
all details of friends (from user table)
rqstFM should be the user logged in and rqstTO must be the friends to whom he sent requests (since request table has request details from all to all users)
status=accepted (they must have accepted the request)
The query I have written is
SELECT *
FROM user
WHERE habits='singing' AND uname = (
SELECT rqstTO
FROM request
WHERE rqstFM ='"+username+"' AND status='Accepted'
);
(here +username+ is the uname of the person logged in obtained from HTML FORM tag). The error I keep getting is "subquery returns more than one row" but I do need multiple rows as logged in user may have sent requests to many ppl and among those all who accepted his request, their details need to be displayed from user table. Please, correct my query or provide an appropriate query for my problem
You need to use IN instead of =:
You can use as mentioned below:
SELECT * FROM user
WHERE habits='singing' AND uname IN
( SELECT rqstTO FROM request WHERE rqstFM ='"+username+"' AND status='Accepted');
However using subqueries are not recommended due to performance issues. You should rewrite your query by using JOIN
You can use 'JOIN' like below: (I haven`t tested it)
SELECT u.* FROM user u
JOIN request r ON u.uname = r.rqstTO
WHERE u.habits='singing' AND r.rqstFM ='"+username+"' AND r.status='Accepted';
You want something like this (not tested it however):
SELECT user.uname, request.fname
FROM user
INNER JOIN request ON request.fname = user.fname
WHERE request.status = 'Accepted';
However, I would probably have a bit of a rethink of those tables, maybe this is personal preference but you would likely be better off having a join table that simply contains an id and the username, and then join on two other tables. One containing the requests and one containing the member details.

MySQL Query to Return Values Not in Database

I am working on a project to assist attendees who are attending specific conferences. I am working on a query to obtain the events in the conference as well as whether the specified user is attending or not attending this event. In order to keep track of whether the user is attending an event, we have a join table (Events_Users), so I'm not sure how to accomplish my task. I need to be able to SELECT all of the information for events and return that, along with an extra column "isAttending" (which is not present in the database) specifying whether that user is attending that conference or not.
I'd like the return result to be something like:
| event.id | isAttending |
| 1 | 1 |
| 2 | 0 |
| 3 | 0 |
Is this possible? (The userId will be passed in so I can check with that to determine if 'isAttending' is true or false).
As a side note, we have already tried making two separate calls (getAllEvents and isUserAttending); however, because these calls are asynchronous we are having trouble getting the information we want (I'm unaware of the details).
Thank you!
Assuming you have these tables
Events : id , other columns
Event_Users : event_id , user_id
Users : id , username
Here is the query whichi will give you idea. If null comes set value to 0 else 1 with IFNULL.
SELECT
e.id,
IFNULL(u.username,0,1) as isAttending
from `Events` as e
LEFT JOIN Events_Users as eu ON eu.events_id = e.id
LEFT JOIN users as u ON u.id = eu.user_id
where u.id = 1
where 1 is the SPECIFIC user id which you can replace dynamically