I've got a website where people can make posts and comment on them. I want to make a new comment notification system, so when a user logs in he can see number of new comments to his posts.
My idea is to add a 'read' table, where I will store user_id and comment_id (means user_id read comment_id). But this can make some performance issue, when table will grow big.
What's the best way to implement this?
One way to achieve that is just to save a created date for post and comment, and a "last visit" date for the user (or "last time the user click on the "show me new post" link).
Then, you just need to get all the post and comment that have a newer date than the one you find in the user table.
How about just storing the user and comment IDs for unread comments instead? Then when the user reads the comment, you can delete that row from the table.
Wouldn't it be better to store the post time in the notifications table and then look for the user's last activity (again storing the value in the users table). Then you could do a simple query:
$lastActivityTime = User->GetLastActivity();
$result = mysql_num_rows(mysql_query("SELECT COUNT(`id`) FROM `notifications` WHERE `postTime` > '$lastActivityTime'"));
Good luck!
You can choose a different storage than mySQL for this data (Like : MongoDB).
Or you can make pub/sub implementation for notifying users. (With using pubsub you dont need to store data. Just notify)
Related
I have a blog and I want to add a function "Notify me of new comments by email" to each post, when the user comments a post.
Im working with PHP and MySQL.
I was thinking about to send a mail to the users who has commented some posts and has checked the checkbox "Notify me of new comments by email" with a query like:
$query = mysql_query("SELECT COUNT(post_id) AS NumberOfComments FROM comments WHERE post_id = $post_id");
$row = mysql_fetch_assoc($query);
if($row['NumberOfComments '] > $NumberOfComments){
mail("someone#example.com","subject","message");
}
But if someone deleted a comment from the post and a new comment has been added then it would be the same number of comments and no mail will be sent. Any ideas on how the query could be better?
It depends on when you want to notify the user.
Do they want to be notified of every comment? Then the functionality which posts the comment would also send the notification. Any time a comment is posted, check for users to be notified and notify them.
Do they want a periodic (daily, weekly, etc.) notification that there exist new comments? Then you still don't want a count. What you want in that case is to check if there exist new records. There are a couple of ways to go about this:
Based on identifiers. If you know the ID of the last comment about which the user was notified (which you may need to store somewhere in a notifications table) then you check if there exist new IDs above that one. If so, there are new comments.
Based on date. If you know the timestamp of the last comment about which the user was notified (which you can store somewhere or calculate on the fly based on the period of notifications) then you check if there exist new comments since that time. If so, there are new comments.
As you've found, simply counting the records isn't a meaningful indication of what you're looking for. All a record count does is tell you how many records there are. If you want to know when those records were posted, you need a timestamp of some kind. If you want to know if records match previously known records, you need an identifier of some kind.
Never assume information derived from data which doesn't hold that information. Store the information you need to know.
Do this mailing on the insertion from the comment to the database, then you dont need this extra query.
EDIT:
So you store the user's who want to get notified in the database
with a table with a id user_id post_id i named it comment_notify
then you can do something like that
// Insert comment to database
$userWhoWantGetNotified = mysql_query("SELECT * FROM comment_notify WHERE post_id = $postId");
while ($entry = mysql_fetch_assoc($userWhoWantGetNotified )) {
$userId = $entry["user_id"];
// get email from user_id
mail(..);
}
I have a table article with many articles. I want to track the number of viewers for each article. Here's my idea, of how I plan to do it.
I've a table viewers with rows: id, ip, date, article_id.
article_id is a FOREIGN FIELD referring to the id of the article. So, when a user open up an article, his/her IP address is stored in the table.
Is this a decent approach? It is for a personal site and not a very big website.
EDIT: I want to print the number of view on each article page.
It depends on how frequently you need to display number of viewer. Your general query will be:
select count(*) from viewers
where article_id='10'
With time, your viewers table will grow. Say it have million records after 1 year or two. Now if you are showing number of viewers on each article page or displaying articles with most viewers, it will start impacting on performance even though foreign key is indexed. However that will happen after you added hundreds of articles with each having thousands of viewers.
A better optimized solution may be to keep number of viewers in article table and use that to display results. Existing Viewers table is also necessary to ensure there is no duplicate entry (Same user reading an article ten times must be marked as single entry not ten).
Use a Tool like Google Analytics. This will do the job much more elaborated and you're up and running in minutes, there's more about unique visitors than IP addresses!
If you want to have an on premise solution, look at PIWIK, which is PHP framework for exactly this puprose.
In this design,There is a one problem if the same user open it again and again then either you have to put check before insert the entry or you insert the same ip address multiple time but different time stamp.
Most of the popular sites consider one ip address as one view even if that client or user open that article several times.
I can think of solution.
your approach with single check. if the same client has opened it again don't insert it.
or group by Id when you retrieve the counter.
It depends on what you want to store in your database. If you want to know exactly how many unique users visited this particular article (including date and ip) this is reasonable way do to this. But if you need only a number to show you can alter article table and include new column with visit_counter and store cookie to prevent incrementing counter on same user.
try something like this
// insert
$query = mysqli_query("REPLACE INTO viewers (ip) VALUES ('" . ip2long($_SERVER['REMOTE_ADDR']) . "')");
// retrieve
list($pageviews) = mysqli_fetch_row(mysqli_query("SELECT COUNT(ip) FROM viewers"));
echo $pageviews;
Read : REPLACE INTO
Yes, this is good aproach if you create some kind of cache for displaying how many views each article had. It's not optimal to count views each time user open website.
You can do it in SQL Server. There is something like materialized view. ( https://code.google.com/p/flexviews/ )
select article_id, count(*) as views from viewers group by article_id
Or you can cache it in files and refresh every X time.
To store users who viewed article I suggest using AJAX. When user open website, another 'thread' will call website to add his as viewer. Even if your db is slow, it will not slow down website loading, also web spiders will not be counted.
I have to create a like system (the name won't be "like", Facebook owns it).
So I imagined two ways to store these likes in my database and I want to know, which way is the better for a very high-traffic site.
Create table comment_likes with "id", "comment_id", "user_id" cells. In comments table store the "like_count", so I don't need to count it when I need to write it out. But likes are easy to do thing, so people will create a lots of them and if I need to list a specified comment's likes, I need to read the whole comment_likes table and found all the user_ids. This could be millions of rows in the future. If 1000 user will do it in the same time, my system will die.
My second thought was, to store likes in comments table. create a cell named "likes" with a list of user_ids like this: 1#34#21#56#....
So when somebody like/unlike a comment just CONCAT or REPLACE his/her id in this cell with a #. When I need to list specified comment just explode this list at #-s.
I think 2nd could be faster and smarter, but what do you think about this?
The first option is much better, because you have the benefits of a relational setup. For example: What if you want to get the comments from the database userId x has liked? With the first setup this is a fast and simple query. In the second case you would have to use a LIKE, which is much slower and inaccurate. (Imagine the userId is 1, and the likes field in the comments table contains #10 - it would return the comment if you would use LIKE '%1%').
And even for a high traffic site; just using an index on commentId would make this a fast operation.
So go for the first option.
If you really doubt the speed of the first option, you could create a "cache" field in the comments table in which you count the amount of likes, so you don't have to perform a subquery to select the like count.
I am still quite new to mysql and I was curious what the best way to go about saving multiple-users' information in a database. I apologize for this question being as clueless as it is, but I have not been able to find any sort of examples or tutorials regarding this subject.
For example, if there are multiple users and they want to log the distance they have ran and then be able to access this information later, can I store their information in some sort of multi-dimensional array which is linked to their username? Is there a way to do this using cookies? Can cookies be stored on the server and then retrieved on a different computer when the user logs in? Or is it as simple as creating a new table for the user and then storing all of the information there?
Any direction you could offer me would be appreciated
You need multiple tables:
User Table:
ID (Auto increment)
Name (varchar)
...more info...
...more info...
etc...
Distance Table:
ID (auto increment)
User_id (Int)
Distance Ran (varchar)
...more info about the trip...
Now, you can do something like this to get all the runs by a certain user:
SELECT * FROM users LEFT JOIN distance ON users.id = distance.user_id WHERE users.id = $user_id
where $user_id is the person's ID. This will give you all the runs that the user did along with their user information
Good luck! Please ask if you have more questions.
P.S. If you plan to keep data for more than a couple hours, you don't want to use COOKIES or _$SESSION vars, because they are prone to expire, and won't be available to users that login from multiple endpoints.
I want to do a function to my users, so on index.php there is e.g:
You have 2 new comments on your clip
How should i do this? I mean i want ideas to do this the easiest way. Table for the videos is member_videos, and tables for the comment is member_videocomments, a comment inside the table is connected by their "videoID", which is the id of the column in member_videos.
Should i do the classic, making a field, which all is 0, until it has been seen by the user its 1 or what should i do.
One alternative to the unread flag on each comment is a last_read_comments timestamp on the user record. Whenever they read their new comments, update the timestamp to the current time. When they land on your homepage, query for all comments newer than that timestamp value.
Why don't you just do a check when you load the video against the comments table that says something like
SELECT COUNT(*) FROM member_videocomments WHERE videoID = videoIDLoaded;
Then get the result set back as an integer and check if that integer is equal to 0, if it is then display 0, else query the database for the comments get the result set back and display all the comments on the page however you like.
Just update a field in the table member_videocomments, something like readbyuser. Leave it at zero until the user views that specific comment.
$result = mysql_query("SELECT id FROM member_videocomments WHERE !readbyuser");
$num_rows = mysql_num_rows($result);
You've given the answer yourself. Just mark the comments when they are actually being displayed to the user. Assuming new comments are not viewed all at once but instead per video clip, I don't think the timestamp approach would be a good solution, because when you update the timestamp once the user has opened one of their newly commented videos, you will lose track of other new comments.
I have a similar situation, and I am using a is_read flag. When comments are added to the database, is_read is set to 0. When a user logs in, I check for any unread comments (it's here that I grab the # of unread comments so I can display it). Then when they view them, I grab the IDs of the comments and run a query to set their is_read to 1.
Matthew's timestamp solution is also good, so really it's up to what you feel more comfortable with.