Database designs for customizable user feeds per group (so not social) - mysql

I'm creating an application where there are multiple groups that contain a feed of messages. I need to know which message is read for X person. The feed should also be customizable per user.
I was thinking about using the following database structure:
messages
- id (PK)
- user_id (user that created the message)
- text
- group_id
- created_at
objects
- id (PK)
- user_id (user that should receive the object in his timeline)
- parent_type (can be `message` or some other resource)
- parent_id (the `id` of the resource based on the type)
- seen (boolean that indicates if the user has seen the object)
When a message is created for a group, I'll create a record in the messages table and create records for every member of the group in the objects table.
The only thing that is currently holding me back is, that there might be groups that consist of ~1000-2000 users at max. For every message created in those groups, there will be created 1000-2000 records in the objects table.
Will this be a problem and how could I solve this if it might be?

Related

Advice on DB Table Structure for Message System

I have not found a tutorial yet on the internet for what I am looking for.
Functionality I am after is a simple message send and retrieve function.
User 1 - Sends Message to User 2
User 2 can view messages in their Inbox
I know I will need 2 controllers one for Handling the message sending and the other to retrieve.
How would this type of system function on the DB side. Do i make a new Table for Inbox and so all messages are sent there with corresponding id of sender and receiver?
A simple 2 tables should be enough for this:
TblUsers (UserId, UserName, Password, FirstName, LastName)
TblMessages (FromUser [fk to tblUsers], ToUser [fk to tblUsers], Title, Content, SentDate, ReadDate, DeletedDate)
Note the DeletedDate is only relevant if you want to enable a recycle bin for messages.
If you want to enable sending the same messages to multiple users, you need a little different schema:
TblMessags(MessageId, FromUser [fk to tblUsers], Title, Content, SentDate)
TblRecipients(MessageId [fk to messages], RecipientId [fk to users], ReadDate, DeletedDate)
Since you require help with the table structure and not with the implementation itself, here is a possible scenario:
A table for all users
A table for all messages
Keep in mind that the users table and the messages table is up to you define the attributes you want to store in them. An initial approach could be:
CREATE TABLE users(userID int, username VARCHAR(30));
CREATE TABLE messages(messageID int, senderID int, recipientID int, title VARCHAR(50), content VARCHAR(1000));
Getting a specific user's Inbox could then be done using the following query:
SELECT *
FROM messages
WHERE messages.recipientID=XXXX
XXXX is of course the userID of the user's inbox you want. This would only get the message data. If you wanted to display the sender data you could join the result of the previous query with a query for senderID or recipientID.
Table structure can be changed according to what type of queries you're anticipating. I believe this should suffice as an initial approach, and then you can analyse whether you need to group or index data that gets requested a lot.
Do I make a new Table for Inbox and so all messages are sent there with corresponding id of sender and receiver?
Basically, yes.
I realize that you want to build a simple message table with one sender and one receiver. You might as well design the tables for one sender and multiple receivers, in case you want to expand your message system.
Let's make the user table.
User
----
User ID
User Name
...
And the message table.
Message
-------
Message ID
Message Sent Time Stamp
Message Text
A user can send more than one message and receive more than one message. So, we build a junction table.
MessageUser
-----------
Message ID
User ID
Sender / Receiver Flag
...
The primary key is (Message ID, User ID). You will also have a unique index on (User ID, Message ID). The primary key allows you to get a message to the user. The unique index allows you to build a list of previous messages for a user.

Update existing values in database

I created a database table with 5 columns uniqueID (auto increment), name, college, mobile, event(check box of 12 event). So my question is each time a user registers the unique id increments and iI want another event to an already existing uniqueId, is there a possible way to add/update this without going all over to the database and editing it there?
OK, following the comments, I suggest you do the following.
You need two tables.
user
- userid (unique, auto-increment)
- name
- college
- mobile
event
- eventid (unique, auto-increment)
- userid (not-unique, connects to the user)
When a user registers, you create the user record and the first event record. Then when the user adds another event, you add another event record.
UPDATE:
I was trying to teach you slowly, but peterm is right in his comment. The best way is actually this:
user
- userid (unique)
- fields relevant only to the user
event
- eventid (unique)
- fields relevant to the event (e.g., date, place etc)
user_event
- userid
- eventid (where you have a unique key that includes two fields, userid and eventid)
You might also have a college record too...
But as I said, I was just trying to get you going in the right direction.

Designing MySql tables for syncing notifications

I am trying to design a notifications architecture where each notification has a UID and needs to be delivered to multiple users. Each user device has a local cache of the latest notifications. When the user device comes online it always checks for any new notifications and pulls all of them meant for that user. The device keeps the UID of the latest notification it synced and uses that UID to fetch newer notifications from the server.
I am wondering the best way to implement this in MySQL tables to make it scalable for more than 500K users.
I have a notifications details table where the notification UID is the auto increment primary key. I would need suggestions about the user mapping table which can be like (ignoring the foreign key constraints)
CREATE TABLE user_notifications_mapping (
user_id INT UNSIGNED NOT NULL,
notification_id BIGINT UNSIGNED NOT NULL,
UNIQUE KEY (user_id, notification_id)
) ENGINE=InnoDB;
but am skeptical if it would be the best performance while making a query like
SELECT notification_id FROM user_notifications_mapping WHERE user_id = <user-id> AND notification_id > <last-notification-uid>
If the table is properly indexed, this design is very suitable. Assuming that only a "small" number of notifications will be returned to one given device on synchronisation, a medium-range server will be able to handle hundreds of such requests per second, even if the table is huge (millions of rows).
Now this table is going to grow very huge. But I believe one given notification needs to be sent to one given device only once. I would consider removing (or archiving in another table) records of this table once a notification has been sent. Conceptually, this table becomes something like pending_notifications.
[edit]
Given the new information, this table is likely to grow beyond practical size. You need to take a different approach. For example, there is probably a way to group your notifications (eg. they are of a given type, or they originate from a given entity in your application). The same concept can be applied to your users: maybe you want some notifications be sent to (eg.) all "customers" or "all "administrators".
The underlying idea is to establish the n-n relationship between two entities of smaller cardinality. You wouldn't model the case "some users receive some notifications" but rather "some user groups receive some types of notifications".
Example:
notification can be an "Announcement", a "Notice" or a "Warning" (notification type)
users can be "Administrators" or "Customers" (user group)
Then the notifications_mapping table would look like this:
+-----------------------+
| notifications_mapping |
+-----------------------+
| notification_type |
| group_id |
+-----------------------+
And the corresponding query could be:
SELECT notification_id
FROM notifications_mapping AS map
JOIN user ON user.group_id = map.group_id
JOIN notifications ON notifications.type = map.notification_type
WHERE user_id = <user-id> AND notification_id > <last-notification-uid>

How to store data like as facebook's "likes"

I have object which store in database, it's a some text with properties.
That text has rating. I need to store this rating, and prevent to one user raise this raiting more than one time. If I store "text id" and "user id" in other table and count all records which have needing "text id" i have too much records in table.
There are two ways:
You can use many-to-many relationship ie use separate table with name like 'user_likes', it will have user_id and like_id columns, both of them are primary key (it makes possible user to like the like_object only once)
Another way - which hightraffic websites use: every user record in user table has columns: likes which is just serialized array or json, whatever. Before update this columns your application retrieve this data and look for particular like_object_id if it doesn't exist - you update your database. Please note that in this case all care about data consistency in your application (for instance like_object_id exists in some user record, but doesn't exist in like_object table) should be implemented in your application code, not database.
P.S. Sorry for my english, but I tried to explain as best as I could.
If I store "text id" and "user id" in other table and count all records which have needing "text id" i have too much records in table.
How do you know what is too many records?
Some of the MySQL tables I support have billions of rows. If they need more than that, they split the data to multiple MySQL servers. 1 million rows is not a problem for a MySQL database.
If you want to limit the data so each user can "like" a given text only once, you must store the data separately for each user. This is also true if a user can "unlike" a text they had previously liked.
CREATE TABLE likes (
user_id BIGINT UNSIGNED NOT NULL,
post_id BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (user_id, post_id),
KEY (post_id, user_id)
);
This example table uses its primary key constraint to ensure each user can like a given post only once. By adding a second index, this helps to optimize queries for likes on a specific post.
This is only 16 bytes per row, plus the size of the index. I filled an InnoDB table with over 1 million rows, and it uses about 60MB.
mysql> show table status\G
Name: likes
Engine: InnoDB
Rows: 1046760
Data_length: 39419904
Index_length: 23658496
It's common to store databases on terabyte-sized storage these days, so a 60MB table doesn't seem too large.
I store the likes with the post itself, but not sure with its performance since non of my websites reached a very heavy load.
but I do the following :
Post {
id int;
likes_count int; // likes count to quickly retrive it
likes string; // id of the users liked this post, comma separated
}
when a user likes a post, (using ajax):
the UI will update directly and show that the user liked the post
ajax will send request to the server with the post id and the user id, then post data will be updated as follow:
post.likes_count += 1;
post.likes += userId + ',' ;
when the user reload the page, it will check if his id is in likes, then it the post will appear as liked.

Database table design - are my fields correct?

I need to sell items on my fictitious website and as such have come up with a couple of tables and was wondering if anyone could let me know if this is plausible and if not where i might be able to change things?
I am thinking along the lines of;
Products table : ID, Name, Cost, mediaType(FK)
Media: Id, Name(book, cd, dvd etc)
What is confusing me is that a user might have / own many products, but how would you store an array of product id's in a single column?
Thanks
You could something like store a JSON array in a text or varchar field and let the application handle parsing it.
MySQL doesn't have a native array type, unlike say PostgreSQL, but in general I find if you're trying to store an array you're probably doing something wrong. Of course every rule has its exceptions.
What your probably want is a user table and then a table that correlates products to users. If a product is only going to relate to one user then you can add a user ID column to your Products table. If not, then you'll want another lookup table which handles the many to many relationship. It would look something like this:
------------------------
| user_id | product_id |
------------------------
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 2 |
| 3 | 1 |
| 3 | 5 |
------------------------
I think one way of storing all the products which user has in one column is to store it as a string where product ids are separated by some delimiters like comma. Though this is not the way you want to solve. The best way to solve this problem would be to have a seperate user table and than have a user product table where you associate userid with product id. You could than simple use a simple query to get list of all the products owned by a particular userid
As a starting point, try to think of the system in terms of the major parts - you would have a 'warehouse', so you need a table to list the products you have, and you are going to possibly have users who register their details with you for regular visits - so an account per user. You would generally hold all details of a single product in the same row of the same table (unless you have a really complex product to detail, but not likely). If you're going to keep track of products bought per user account, there's always the option of keeping the order history as a delimited list in a large text field. For example: date,id,id,id,id;date,id,id. Or you could simply refer to order numbers and have a separate table for orders placed [by any customer].
What is confusing me is that a user might have / own many products, but how would you store an array of product id's in a single column?
This is called a "many-to-many" relationship. In essence you would have a table for users, a table for products, and a table to map them like this:
[table] Users
- id
- name
[table] Products
- id
- name
- price
[table] Users_Products
- user_id
- product_id
Then when you want to know what products a user has, you could perform a query like:
SELECT product_id FROM Users_Products WHERE user_id=23;
Of course, user id 23 is fictituous for examples sake. The resulting recordset would contain the id's of all the products the user owns.
You wouldn't store an array of things into a single column. In fact you usually wouldn't store them in separate columns either.
You need to step away from design for a bit and go investigate third normal form. That should be you starting point and, in the vast majority of cases, your ending point for designing database schemas.
The correct way of handling variable size "arrays" is with two tables with a many to one relationship, something like:
Users
User ID (primary key)
Name
Other user info
Objects:
Object Id (primary key)
User id (foreign key, references Users(User id)
Other object info
That's the simplest form where one object is tied to a specific user, but a specific user may have any number of objects.
Where an object can be "owned" by multiple users (I say an object meaning (for example) the book "Death of a Salesman", but obviously each user has their own copy of an object), you use a joining table:
Users
User ID (primary key)
Name
Other user info
Objects:
Object Id (primary key)
User id (foreign key, references Users(User id))
Other object info
UserObjects:
User id (foreign key, references Users(User id))
Object id (foreign key, references Objects(Object id))
Count
primary key (User id, Object id)
Similarly, you can handle one or more by adding an object id to the Users table.
But, until you've nutted out the simplest form and understand 3NF, they won't generally matter to you.