Is there a scalability issue in having a one-to-many relationship between participants and conversation? - relational-database

I have a database design as shown in following entity-relationship diagram (ERD):
https://app.dbdesigner.net/designer/schema/0-social_media-00a3405c-0bcd-4809-9f8e-e86c1b8e5f33
I was wondering if I should have a one-to-many relationship between Participants and Conversation.
Issue: need many joins
The issue is that we need to make a join every time we want to get the id of the Participants of a Conversation to broadcast Messages.
Not only that, but we also need the content of the Messages, meaning we need to make two joins between three tables.
Questions
Is there a more scalable solution for this?
Is there any bottleneck issues?
Is there anything else wrong with the table aside that as an added bonus?

Scalable because:
If one conversation attracts more and more Users (in their role as participants), you simply have to add rows in the table Participants. Imagine the conversation has a members-list, it's called Participants.
If one User account was deleted, you simply have to search for all his records (associated conversations) in table Participants and delete them as well.
Both cases mean only a modification of Participants, whereas the conversation remains untouched.
Associative Entity
This membership or relationship of User to Conversation is bridged by a so-called associative relationship, associative table or associative entity. Means one User can attend (participate in) 0 or many Conversations, vice-versa one Conversation can have (at least) one (the creator) or many participating Users.
So the entity/table Participants acts like a bridge: connecting two sides/perspectives.
Broadcast Example
User A wants to broadcast a message to the channel/conversation 1. Now the system needs to determine all recipients. So look only within table Participants for the conversation 1 and find their attending Users A, B and C. All except the sender A should receive the broadcast: B and C.
There was no join involved. A simple query: SELECT user_id FROM participants WHERE conversation_id = 1 AND user_id <> 'A'. Given the Message and assuming that user_ids can be used directly as destination (email-address, phone-number, etc.), the system can immediately send the broadcast out.

Related

SQL Database Structure for Users + Memberships + Groups

I'm developing an e-commerce site and I wanted to get this community's thoughts on a database structure for groups, users, and their memberships.
THE GOAL: Determine a user's group membership(s) and access privilege at login. A user could be a seller on this site, an admin, a site support, or ANYTHING. Must be scalable.
INITIAL THOUGHT: Three separate tables: users, groups, and memberships. At a successful login, search the membership table for the user's ID and get group ID's from that same row in the membership table. From there, another query to get group information from the groups table (like name of group, description, etc). Store the memberships in the user's session and call it a day.
THE CONCERN: At log in, I don't want to unnecessarily perform additional queries. The above "initial thought" consists of 3 separate queries at login.
THE QUESTIONS:
Is this the right approach?
Any better design solution(s)?
Better to break admins into their own table, or toss 'em into the same groups table?
The database design is reasonable. As a user can belong to multiple groups and can have multiple memberships, two additional tables USER_GROUP and USER_MEMBERSHIPto hold the relations between users and groups and between users and memberships will be necessary.

mysql: Complex conditional query before group by

I have a Postings table (with data of people posting a service they offer) and a table of people that have corresponded (written mails) to these Posting authors thus starting a Transaction (inserted into a second table: Transactions).
Each Posting can have many transactions. Each time a user Logs-in he/she (Transaction_Taker) can send mail to the author (Posting_Author) of his choice.
Each first mail generates a new Transaction and its Transaction_Id (int) is appended to Postings table in the varchar, hyphen-separated Posting_Transaction_List field.
The contents of each subsequent mail that same (logged-in) user (aka Transaction_Taker) sends, does not create/insert a new transaction (nothing inserted to field Posting_Transaction_List) but rather is appended (update) to the Transaction that was started initially by that user for that Posting.
For easy navigation and search, once a user has logged in, I show an ajax generated list of all these postings such that each Posting only shows once though it can have many transactions. In other words I need to show a list of all available Postings including the ones this (logged-in) user has started a Transaction for, but these postings (the ones in which this user has an ongoing transaction) should show, but we should not show that same Posting with OTHER user's transactions. That is, only the logged-in user should see his/her transactions.
Assuming I have table Postings with fields: Posting_Id (int), Posting_Author (varchar), Posting_Content (text), Posting_Transaction_List (varchar)
…and table Transactions with fields: Transaction_Id (int), Transaction_Posting_Id (int), Transaction_Taker_Id (int)
I am (almost) achieving my goal with the following SQL:
$AlmostGoodSQL = "SELECT *, Posting_Id FROM Postings LEFT JOIN Transactions ON
Postings.Posting_Id = Transactions.Transaction_Posting_Id WHERE Posting_Content
LIKE '%"+$SomeSearchString+"%' GROUP BY Posting_Id";
The problem is this shows a distinct instance of each Posting, but not necessarily the ones that have to do with the logged-in user (in the case where there are many transactions -including hers- for a Posting). To do this, I would need to select ALL Postings without transactions attached PLUS those that have Transactions just for this user BEFORE doing the group by. This is what I cannot achieve. I believe that due to the way 'group by' works you could maybe select maximum or minimum values, but not an exact match, say for all the Postings that have Transactions with user (Transaction_Taker) '123456'. I think "group by" shows whichever instance it finds first. How to make it match my criteria?
It does not look like a subquery would do, but rather like something conditional, like: "Search for all Postings and if the Posting has a Transaction listed in the Posting_Transaction_List that points to a Transaction where the Transaction_Taker_Id is the one of the logged-in user ($UserId), then show it distinctly (just that one, once)"… and I don't know how to do all that in SQL: Can anybody please help?

Relational Database: Variable Fields

I am making this hotel reservation program and i'm in a dilemma.
I have the users table that is basically
id
identifier
password
realName
cellphone
email
The rooms table
id
type
price
And the reservations table
id
checkin
checkout
room_id
nights
total_cost
The problem is that a single user in a single reservation can ask for multiple rooms with multiple check ins and outs.
What would be the best approach to achieve this? I was thinking of splitting the various rooms with different reservation ids and then make some kind of workaround to relation them.
I think your data structure is fine as far as it goes. You have two choices.
The first is to relax your language. Don't say that "a single user in a single reservation can ask for multiple rooms with multiple check ins and outs". Instead say, "a single user can make multiple reservations at the same time". Just changing this language fixes your conundrum.
If you really have to tie things together, I might suggest having an column that groups reservations made by a single user together. This could be a full-blown entity, which would have a foreign key reference to another table. Or, it could simply be an identifier, such as the first reservation in the series or the user id with a date/time stamp. I'm not sure that a full blown entity is needed, but you might find it useful.

MySQL Tables Arrangement

I have a corporate website which is used to communicate between staff members as well as staff members with clients. There are internal users who can login and work with their mail using web interface, there is a list of external clients with email address and phone numbers which internal users can use to write an email or make a call. Sometimes clients become staff members, sometime staff members gets fired but stays in the database as they can become future clients.
There are two MySQL tables for those two types. First one is a full list of all people, and there is a separate table of internal users partially duplicating the first table. The second table for the people who can login so it has login, password and some permisisons fields but it also have last name, first name, job, address etc. which is already in the first table.
So all internal users have two entries - one entry at the users table and one at people table. People table has internal users and all the external clients data.
I'm thinking to make one table from those two just by adding internal users fields to the people table such as login, password, permissions etc. so whoever have those fields filled considered to be internal users. That would probably simplify my SQL queries and get rid of edless SQL JOIN constructions as I constantly have to fetch data from both of the tables in order to get full data on a user.
Basically I want users table to become part of the people table. Is there any negative consequences per your experience may be in terms of security or conviniency that can be a problem for such an integration of clients and users being put together in one table?
I don't think you should get rid of the users table. The distinction between internal and external users is too important to depend just on the use of columns.
Instead, make users a "subtype" of people. So keep the people table and include all the users in them, with the appropriate "people" fields. Then in your users table, include the internal information along with a people id.
With this structure, it is easy to get "everyone" (from people) and "internal users" (from users). To get external users, you need to do something like:
select p.*
from people p
where not exists (select 1 from users u where p.personid = u.personid);
This should be a fast operation, with a index on personid. You could maintain a flag in the people table, indicating whether someone is or is not a person, but you would need a trigger to keep it up-to-date. Probably not worth the effort.

MySQL question for conversation app

I have an app that manages conversations between users on a website. It does one to one conversations as well as having multiple people in a single conversation.
Here is the layout for the mysql tables
conversations
conversations_meta
The conversations_meta table links users to the conversations by logging user_id and conversation_id. It also holds meta info about the conversation specific to each user in the conversation.
What I am having trouble with is detecting if a conversation with the same people already exist.
For example if a conversation between Eric Jason and bob exists but maybe it's old and the user forgot about it and then tries to create an addition conversation with the same users I would like to notify them of the conversation.
So the query should look in conversations_meta table and compare user_id and conversation_id to see if the same conversation exists already. Also I wouldn't want it to return conversations that include all the same users and additional users as well.
The main reason I posted this question on here is to get the fastest query possible to accomplish this task since there will be thousands of conversations.
What about this:
SELECT conversations_meta.conversations_id FROM conversations_meta
where (conversations_meta.user_id=1) or (conversations_meta.user_id=2)
group by conversations_id HAVING count(*) = 2
NOTE: this is a case for only 2 people in the conversation. Easily expanded to the case of 3 or or more.