How to maintain read/unread messages by php - mysql

This question might have been asked many times before this post, but I could not find a suitable answer which perfectly did what I want.
Suppose I have two tables:
table-1: table_msg
-------------------------------------------------------
msg_id | msg_subject | create_time
-------------------------------------------------------
1 | welcome to this site | 2015-01-01 10:20:30
-------------------------------------------------------
2 | How to visit this site | 2015-01-05 10:30:00
--------------------------------------------------------
3 | Plz pay your member fee | 2015-03-10 09:00:00
--------------------------------------------------------
4 | Important Notice | 2015-06-01 12:20:00
--------------------------------------------------------
5 | Plz change your password| 2015-06-15 13:24:01
--------------------------------------------------------
table-2: table_user
-------------------------------
user_id | last_login
-------------------------------
1 | 2015-03-01 07:00:00
-------------------------------
I see solutions almost all the time, that as user_id-1's last login was before msg_id-3, so if the user_id-1 logins on 2015-06-02, he has 02 new messages msg_id-3 and msg_id-4. Well I can bold the subject of these two messages by css to show it as UNREAD. Now suppose after login user_id-1 opened msg_id-4 and did not opened msg_id-3, so the msg_id-3 is still UNREAD.
Now when the same user again login on 2015-06-20, then after his last login, msg_id-5 can be easily identified as UNREAD as it was posted after his last login 2015-06-02, it can be made bold, but what about msg_id-3 which was posted before his last login but still not opened. It is also UNREAD and should be in Bold font.
How can I identify msg_id-3 as UNREAD without a separate table like below:
table-3: read_msg
------------------------
id | user_id | msg_id
------------------------
1 | 1 | 1
------------------------
1 | 1 | 2
------------------------
1 | 1 | 4
------------------------
table-3 is well for a few users, but if users are 5000 in numbers and total messages are 10000 or higher then the table would be a quite large to handle for mysql engine and it will grow geometrically larger even day by day.
Is there any mechanism/technique or algorithm so that together with message that were posted after last login, message which were not opened before last login can also be identified as UNREAD without a huge size read_msg table?

why not just add a column (boolean) with the status (1 = read, 0 = unread) to your table, which upon opening a certain message updates the status to read.
table-3: read_msg
id | user_id | msg_id|read
1 | 1 | 1|0
1 | 1 | 2|1
1 | 1 | 4|0
consider the following scenario:
A user logs in and has 7 unread messages. he chooses to read only 1. If you create a query/algorithm to use his last login time to see unread messages, it will see that he logged in after the messages were posted. but did he read them? no ...

I just noticed that, as you've described, you have one table that has the messages. These messages are for everyone. I think that davejal assumes, as I did, that these messages were directed towards each user. In which case, you would have one row in table_msg per message per user. To get the messages for that particular user, the table would have to be:
msg_id | msg_subject | create_time | read |user_id|
--------------------------------------------------------------------------
1 | welcome to this site | 2015-01-01 10:20:30| 0 | 1
--------------------------------------------------------------------------
2 | How to visit this site | 2015-01-05 10:30:00| 0 | 1
--------------------------------------------------------------------------
3 | Plz pay your member fee | 2015-03-10 09:00:00| 1 | 1
--------------------------------------------------------------------------
4 | Important Notice | 2015-06-01 12:20:00| 1 | 1
-------------------------------------------------------------------------
5 | Plz change your password| 2015-06-15 13:24:01| 0 | 1
----------------------------------------------------------------------
Then you would simply do:
select * from table_msg where user_id = 1 and read = 0;
This is the only way I can think of that would avoid having the third table read_msg. The table can get large as some messages will be duplicated, but you can always delete old read messages if you're concerned about that.

Related

How to handle friend request accept logic in database?

I am working on a simple social app and have a user_friend table which has both the user_id and friend_id as its composite keys. In the front end, the current user can look at other people's profiles and then click on add friend button which updates the user_friend table. For example, user with id 100 can view user with id 9's and 15's profiles and click on add button and then the user_friend table gets updated as
user_id: 100, friend_id 9
and
user_id: 100, friend_id 15
What is the best approach to handling such request? I was thinking creating a new table called request_table which has requester column which has the id for the user, accepter column which has the id for the friend and status column with accepted and pending. So, when requester clicks add friend button, the status gets updated to accepted which then updates the user_friend table to to reflect the change (by adding a new row user_id: 9, friend_id 100 in the above example).
Please advice if there are cleaner or better ways to do this.
I would make it much simpler than you are thinking .. Your current table looks like:
+--------------------------------+
| user_id | friend_id |
+--------------+-=---------------+
| 100 | 15 |
+--------------+-----------------+
| 100 | 9 |
+--------------+-----------------+
Add two columns .. requested and accepted:
+--------------------------------+-----------------+----------------+
| user_id | friend_id | requested | accepted |
+--------------+-=---------------+-----------------+----------------+
| 100 | 15 | 1 | 0 |
+--------------+-----------------+-----------------+----------------+
| 100 | 9 | 1 | 1 |
+--------------+-----------------+-----------------+----------------+
Although one could ASSUME that if the entry is in the table requested will always be 1 -- So really you only need to add the accepted column .. But you get the basic idea/principle.
NOTE if you need more statuses than just "accepted" like -- Say "blocked" or "suspended" etc etc you can create a third table and use the in a relational way.
+-----------------------------------------------------------------+
| user_firends (uf_id for indexing FASTER) |
+--------------------------------+-----------------+--------------+
| uf_id | user_id | friend_id | status |
+--------------+-=---------------+-----------------+--------------+
| 1 | 100 | 9 | 1 |
+--------------+-----------------+-----------------+--------------+
| 2 | 100 | 15 | 2 |
+--------------+-----------------+-----------------+--------------+
+---------------------------------------+
| statuses_table |
+------------------+--------------------+
| status_id | status |
+------------------+--------------------+
| 1 | requested |
+------------------+--------------------+
| 2 | accepted |
+------------------+--------------------+
| 3 | rejected |
+------------------+--------------------+
| 4 | blocked |
+------------------+--------------------+
many (users) to many (friends) with a users_friends "pivot" table AND
many (friends) to single (staus) with a direct insert of status in the column

Users queue in mysql

I'm trying to create queues table
id | queue_id | user_id | is_active_to_vote
1 | 14 | 1 | 1
2 | 14 | 2 | 0
3 | 14 | 3 | 0
4 | 15 | 1 | 1
5 | 15 | 2 | 0
6 | 15 | 3 | 0
the users list in result looks like this (for queue_id=14)
Sam (user_id=1 votes now)
John (user_id=2)
Bill (user_id=3)
But if user did not vote in time I need to resort the queue like this
John (user_id=2 votes now)
Bill (user_id=3)
...
Sam (user_id=1 last user in queue)
What is the good way to do this?
Since you're using "did not vote in time" information in order to sort your queue, you need that information on voting time somewhere - either in a new field in your current table, or in a separate table.
Once you have that, you'll be able to sort the queue based on the criteria you want (which aren't clear to me at this point - is it user_id by default ?).
Note that in general I would advise you to perform queue management in your application controller, not directly in MySQL.

Creating a waiting listing system and re-ranking users

So here is my problem, I am working on a wait listing system for an app. A user would sign up to be notified when we launch, and offer referral links to help "boost" their spot in the wait list.
The problem I am having is how should I rank them inside of a MySQL or NoSQL database. The issue I am running into is this, if my database looks like this:
User | Ranking | Invited
-------------------------
user1 | 1 | 0
user2 | 2 | 0
user3 | 3 | 0
user4 | 4 | 0
user5 | 5 | 0
user6 | 6 | 0
user7 | 7 | 0
user8 | 8 | 1
Now, assuming user8 now invites 1 friend. They get bumped up to the top, but how do I go about sorting this data? It is fine reordering the entire table to look like this:
User | Ranking | Invited
-------------------------
user1 | 2 | 0
user2 | 3 | 0
user3 | 4 | 0
user4 | 5 | 0
user5 | 6 | 0
user6 | 7 | 0
user7 | 8 | 0
user8 | 1 | 1
But not very practical if the records go over a few hundred. Maybe I am not looking at this problem the right way? There must be a simpler solution? Any pointers or help is appreciated! Thank you.
If you want the ranking to be based on who has invited the most people, and if the same number of invites, their original rank, just sort that way when you read the table:
select user from waitlisttable order by invited desc, ranking;
If you need that order in some larger query, you could create a view for that, but actually updating the rankings for all existing records should definitely be avoided.
If you want to get the "rank" for all the users, see How to show sequential number in MySQL query result.
If you really need to be able to look up a single user's rank, then you probably do need to update all the rows; depending on how heavy your load is, you would either do so every X minutes by some job, or each time a row is updated via a trigger. A simple example of doing the former would be:
set #rank:=0;
update waitlisttable set ranking=(#rank:=#rank+1) order by invitations desc, initial_ranking;

Improve relationship between 3 tables in MySQL

I have 3 tables on my database: users, payment_methods and user_blocked_pm. The users table speaks for itself, the payment_methods stores all the payment methods the company uses, and the user_blocked_pm has the payment methods blocked for a specific user.
+------------------+
| users |
+-----+------------+
| id | user_name |
+-----+------------+
| 1 | John |
| 2 | Davis |
+-----+------------+
+-----------------------+
| payment_methods |
+-----+-----------------+
| id | payment_method |
+-----+-----------------+
| 1 | credit_card |
| 2 | cash |
+-----+-----------------+
+-----------------------------------+
| user_blocked_pm |
+-----+---------+-------------------+
| id | user_id | payment_method_id |
+-----+---------+-------------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
+-----+---------+-------------------+
So, following the structure above, both payment_methods are blocked for the user John and cash is blocked for Davis.
Following this structure when there are multiple users and payment methods I'll have multiple records on user_blocked_pm because each user will be allowed to use only a few of the payment methods.
Is there a better way to work this relationship between the users and the user_blocked_pm so that the table doesn't get gigantic?
You do not need the id column in user_blocked_pm table because you going to select on user_id or pm_id
If the number of the allowed pm is less then the number of the not allowed, why not to make a user_allowed_pm table instead of user_blocked_pm
If you have a fixed number of pm for each user then you do not need a table just you create a column for every pm and you put the key of the pm (like a foreign key)
If you have a few user "types", then perhaps you can replace the user_blocked_pm with a user_type_blocked_pm. A "type" is a set of blocked/permitted payment methods. So the user_type_blocked_pm table is small -- has entries for the different types (users who can pay with cash only, users who can pay with credit and cash, etc. ) Then, you can add a column to the users table to indicate the user type.
Your method is fine, and the other ideas so far suggested are also fine. If the number of payment types is small (not more than 7, say - and certainly less than 64!), and finite, then you might also consider a bitwise method, where 1 = credit_card, 2 = cash, and 3 = both. I do this for days of the week, which are unlikely to ever be more than 7.

mysql user row level access

Have a database with the following
id | userid | name
1 | 1 | John
2 | 1 | John
3 | 2 | Joe
4 | 2 | Joe
5 | 2 | Joe
6 | 3 | Sue
7 | 3 | Sue
I need to get a way that I can create a database, then create users. Each user that I create in mysql limit them to access of data for their userid. Every database table in the database has the userid value.
So whether they are reading ,updating, insert or delete. If it is going through a specific mysql user that I attached to that database, I want that user to only read, update, insert or delete where their userid is.
I have read some things on mysql triggers but have not found anything that will work for me.
We have a backend that has data in it and restricted by userid.
The website pulls data from that table based in userid so select * from articles where userid=1. Right now, that code is modifiable by the user. I would like a way to go select * from articles and mysql only results rows that have userid=1 for that mysql user. The goal would be for every user to have their own mysql user login to the mysql database that would restrict to that specific value of userid that is theirs.
Any thoughts? Thanks so much!
GoogleResult[0] has this:
http://www.sqlmaestro.com/resources/all/row_level_security_mysql/
Abstract
The article contains a step-by-step guide to implementation of row level security in MySQL 5.0 and higher using such MySQL features as views and triggers.
Well! i will suggest to make a table for that. For the whole application
user_rights
id | user_id | insert | update | delete | read
1 | 2 | 0 | 0 | 0 | 1
Note : 1 for allowed and 0 for disallowed.
Now before you do anything first check the rights then perform other actions.
Detailed method including parts of application :
screens
id | title
1 | articles
2 | blog
user_rights
id | user_id | insert | update | delete | read | screen_id
1 | 2 | 1 | 0 | 0 | 1 | 1
2 | 2 | 0 | 0 | 0 | 1 | 2
In this method you can allow screen level access. User id 2 can add and view articles and he can aslo view blog but.
I may be using inappropriate terms here
but i hope you get the idea.