Get the first message of every conversation - sql

I have one table to store all the messages sent inside of a xmpp service. I'm looking to create a query to get all the conversations and the first message of it (like whatsapp in chat logs).
Here is my table.
FromPersonId and ToPersonId are ids for people. What I do is, for example I want to see all the conversations of the personId = 643
SELECT DISTINCT MA.FromPersonId, MA.ToPersonId, MAX(MA.SENTDATE) AS [Date], Body
FROM MessageArchive AS MA
WHERE MA.FromPersonId = #personId OR MA.ToPersonId = #personId
GROUP BY MA.FromPersonId, MA.ToPersonId, Body
ORDER BY [Date] DESC
Above is what I have. And the result is
As you see, the result is for the same conversation. But cannot distinguish that is the same conversation because are the same people but in different position.
How can I fix this?

You miss the 644 to 643 message, supposing it exists, What I recommend is to put a ROW ID autoincremental, this columns can give you exact information about what records come first and what records come after, besides, How do you identify that the message is the same ?

You are missing a 'conversation' table, with a conversationID field being a foreign key in your MessageArchive table, as a manifestation of the 'one-to-many' relation existing between the conversation entity and the message entity: one conversation holds at least one message, and each message relates to one, and only one, conversation.
With such a database model, you would be able to collect the 'top 1' message of each conversation.

Related

Need help getting the last message from a conversation between two users

I am currently building a messaging feature and my goal is to get the last message between two users (a message inbox). And then when a user clicks on the last message, a full conversation between the two users will show. I currently have a messages table with the following data:
create table messages(
message_id serial primary key not null,
user_id_sender integer,
user_id_receiver integer,
subject varchar(100),
message text,
seen boolean default false,
date timestamptz
)
My question is, is it better to create a inbox table to log the last conversation between two users, or is there a query to find the last message between the two users and display that message with just the messages table. I have looked into and tried using CTE's, triggers and playing with SELECT DISTINCT that other have posted to no avail. I'm using React for my front end and get duplicate key issues with left joins with null values. Please I would like to know A.The best way to approach and normalize the data and B. Find the best query that would produce the desired result
Any help would be appreciated I'm just trying to find the right path and the best things to look into and learn to solve this kind of problem.
I have tried using CTEs, triggers, SELECT DISTINCT
If you are looking for a better option as per your question is it better to create a xxx table, then the answer is yes for retrieval of your latest message assuming you are storing only one record with the last message in that table xxx and the same record would be updated with the recent message always. You can update this table in your main table trigger (i.e. messages table) and the downside would be little performance hit during the insertion you can take a call on that after you check with a load test.
Coming to your second question is there a query to find the last message using the messages table; you can have a subquery to select the MAX of date from the messages table and then use that date in your main query like date = ( select max(date) to get the latest message. Make sure to create an index on the date column and also, for better performance add an additional where clause on the date column (for example date should be greater than the current date minus 30 days) in the main query.

How to know how many unread group messages I have

I'm designing a database. This is what I have to represent:
A user can have 0..n friends.
A user can send 0..n messages to a friend.
A user can be member of 0..n groups.
A group can have 1..n members.
A user can send 0..n messages to a group.
To manage conversations between users, and group I have a table (Talk) with these columns:
TalkId (NOT NULL, PK)
Type (NOT NULL, values: UserTalk or GroupTalk)
StarterUserId (NOT NULL, the user that has started the talk).
RecepientUserId: (NULL, the user that has received the first message. NULL if it is a GroupTalk).
DateStarted: (NOT NULL, when the talk has been started).
GroupId: (NULL, the group that owns the talk. NULL if it is a UserTalk)
I also have a Message table to store all the message for each Talk. This Message table has a column Read to indicate that the recipient has read or not the message.
If user 1 sends a message to a user 2, first I check if there is a Talk row with:
((StarterUserI == 1 and RecepientUserId == 2) OR
(StarterUserI == 2 and RecepientUserId == 1))
If there isn't, I create a new row on it. Then, I insert the message in Message table with Message.TalkId pointing to the row that I have created.
My problem is that I don't know how to know how many unread message a user has for a group talk.
For a user talk is easy checking if Message.Read column is false.
To know if a user has unread messages on a group's talk, I can insert the same message for each group member, changing the recipient. For example:
I have a group, with three members. Member 1 send a message to a group. I have to insert a message to user 2, and the same message to user 3:
But, this can make grow Message table very fast.
I've thought to add new two columns to Talk table, the date for the last message sent to that talk, and the id of user that has sent that last message. If I have the date and the ID for the last message in a talk, I can check if there are new messages, but I can't know how many.
I have also a UserGroup table to store the users that are members of a group, and the users' groups. I can add a new column to this table to store how many messages a user has for a group talk. Every time another user send a message to that group, I'm going to insert a new row on Message table, and increase the value on UserGroup.Unread by one. But I think I'm going to mess the design.
How can I know how many unread message a user has for a Group Talk?
You can add a new table MessageStatus with the columns UserID, MessageID and Read where you add one row for each recipient of a message (UserTalk or GroupTalk). This avoids the redundancies you would introduce when duplicating rows in the Message table.
For convenience you could introduce an INSERT-trigger on Message to create the rows in MessageStatus.

SQL - enhance schema to count unread messages

I have a simple message schema where a "thread" ties 2 or more users to a stream of messages. Each message belongs to a single thread. It works just like SMS messages, or Facebook messages.
I only need to count how many threads have new messages for a given user. When a user opens a thread, I need to update the db (for that user only), indicating that they have looked at the thread. Given these 2 tables, how should I enhance my schema to store this "updated thread" data for each user in each thread?
MessageThreads:
threadID
lastUpdated
MessageThreadUsers:
threadFK
userFK
I'm thinking along the lines of adding this table (but is there a better way???)
UserThreads
userFK
threadFK
lastChecked
You should be able to just add a lastChecked column to your MessageThreadUsers table. Then you can compare that value to the lastUpdated field in MessageThreads to determine whether the user has new messages. Or something like below should give you the total number of new messages.
SELECT COUNT(mtu.*) FROM MessageThreadUsers mtu JOIN MessageThreads mt ON mt.threadID = mtu.threadFK WHERE mtu.lastChecked < mt.lastUpdated GROUP BY mtu.userFK
What about some kind of unread boolean value in MessageThreads? When a thread is updated, unread is set to true. When a user checks a thread, set it to false.
Just a thought.

A way to query both news feed and wall using a single request

I'm trying to find the best way to query both news feed and wall using a single request.
First attempt:
Query me/home and me/feed in batch request.
Problem: querying me/home gives me bad results due to Graph API bugs (showing blocked items and on the contrary not showing some items that should be shown) so I decided to change to FQL which seems to handle it much better.
Second attempt:
Use single batch request to query:
(1) me/feed directly.
(2) fql.query for stream table with filter_key set to 'others'.
Problem: Needs to also query for user names because the stream table contains only ids.
Third attempt:
Use batch request to query:
(1) me/feed directly
(2) fql.multiquery for stream table with filter_key set to 'others' and the names table with "WHERE id IN (SELECT actor_id FROM #stream)".
Problem: Fails. It returns "Error: batch parameter must be a JSON array" although it is a json array.
Fourth Attempt:
Use fql.multiquery to get news feed stream, wall stream and names.
Problem: I have no idea how to get a view similar to me/feed using FQL. The best I could get is a list of all my own posts but it doesn't show photos the user is tagged in (so I guess more things are missing).
Appreciate any hints.
Due to FQL not doing SQL style joins, getting information from multiple tables in one query is currently impossible.
Use FQL on the stream table to get the list of posts you want to display be sure to grab the source_id. The source_id can be a user id, page id, event id, group id, and there may be more objects too, just don't remember off the top of my head. (You may also want to do similar caching of the actor_id, target_id and viewer_id)
Cache the source_ids in a dictionary style data cache with source_id being the PK.
Loop thru the cache for ones you don't have information on
Try grabbing the information from the user table based upon id, then next the page table, then event table, and group table until you can find what that ID belongs to. Store the information in your cache
For display merge together the stream table items with the source_id information.

How would I use metawhere to search through associations and join the tables?

I have two models: Message and UserMessage. I got this architecture from somewhere else on SO, but am having some challenges.
Each Message has TWO UserMessage: one UserMessage has a user_id of the sender, and the other has a user_id of the recipient. This allows one party to delete or change the status of the message separate from the other.
How can I find a list of all Messages that were sent between sender_id and receiver_id?
If I do a UserMessage.where(:user_id => sender_id) that doesn't show me just the recipient, for example.
Also: one Message may have many UserMessages, so I need to be able to uniquely find or group by the Message. In other words, five UserMessages all belonging to the same Message I would just want the latest dated UserMessage for that Message.
I am thinking if I can generate a list of all Messages where one UserMessage is sender_id and the other is receiver_id, that would work, but how would I do that?
You are contradicting yourself. At first, you say "Each Message has TWO UserMessage", and then "five UserMessages all belonging to the same Message". If you could rephrase the question to make this understandable it would be easier to help you.