Up vote and down vote in Laravel eloquent - php

I want to create an up vote and down vote system for my website where a unique user can vote up/down for one post and next time he only allow to opposite to get off from database and after that he again can up or down vote.
In this case I have:
users table :
id
name
debates table :
id
post
upvotes table:
id
user_id
debate_id
and similarly downvote table:
id
user_id
debate_id
Is that a good way to manage and track up vote and down vote concept?

I think, you can use a single table to track the votes and the structure could be something like this
Table : votes
id | user_id | debate_id | vote
Here, vote field could be tinyInt with defauld null.
And, in vote field, you just keep two different values depending on the vote type, for example, if a user up votes then insert a value of 1 in the vote field and for down vote, insert the value of 0. So, your table may look something like this
id | user_id | debate_id| vote
1 | 10 | 4 | 1 <-- up
2 | 11 | 4 | 0 <-- down
3 | 12 | 4 | 1 <-- up
In this case, two users with id = 10 and id = 12 up voted the post whose debate_id = 4 and another user with user_id = 11 down voted on the same post.
IN this case, you may find out how many up or down votes a post got by counting the vote field's value, for example, you may count for up votes for debate_id = 4 using something like this
$count = Debate::where('debate_id', '=', 4)->where('vote', '=', 1)->count();
Also, you may use something Query Scope, this is just an idea and it's not possible to make an answer which covers everything in this scope. You should start using some basic idea and if you stuck at a certain point, then you may ask specific questions with your code.
Also, I would like to mention that, if you find a user id in the votes table with a certain debate_id then this user has voted on this post and to find out the vote type, just check the vote field 1 or 0.

I would prefer to only have one table containing the votes, this could be done with an extra column such as is_downvote int(1).
It seems that you havn't tried much which is always a negative. For this scenario the Laravel Eloquent Documentation should be plenty to figure this out.
I would of written this as a comment but it's pretty lengthy now.

Related

Save statistics of wrong questions answers to database

I'm making a quiz game, and I want to make statistics of questions that has been answered wrong.
I have a database with 3 tables: Questions (all questions), Answers (the alternatives for each question), Games (stats about each game sessions).
Right now I'm thinking of two alternative ways to make a solution for this.
Save each question ID into an array, then save the array
into one record in MySQL at the end of the game.
Insert a new record with question ID into the table for each wrong
answer.
Which of these options would be the best approach to solve my problem? If I'm correctly, the last one will be easier when I'm gonna query the database to show questions that has been answered wrong. Any input or suggestions would be appreciated!
My advice is to save each answer given into a separate row, exactly for the reason you stated. Querying such a structure will be much easier than having multiple answers stored in a single row.
I would structure the tables as follows
Question
ID | Text | whatever else you may need
Answer
ID | QuestionID | Text | IsCorrect | whatever else you may need
Game
ID | User | StartTime | EndTime | whatever else you may need
Stats
ID | GameID | QuestionID | AnswerID | AnswerTime | whatever else you may need
This would need adjustments depending on the kind of analysis you're planning to do on it, but you get the idea.
Counting the number of times a wrong answers has been given would be as easy as
select t1.ID, count(*)
from Answer t1
join Stats t2
on t1.ID = t2.AnswerID
where t1.IsCorrect = 'N'
group by t1.ID
I am not sure I understood correctly your question. What follow is a possible solution for table statistics for answers if you want detailed information for each question / answer :
CREATE TABLE GAME_STATS (ID INT NOT NULL, ID_QUEST INT, ID_ANSWER INT, NUM INT);
ID is a sequence (you could omit this and make PK ID_QUEST, ID_ANSWER)
ID_QUEST refers to ID of table Questions
ID_ANSWER refers to ID of table Answers.
NUM is the number of times that answer has been selected.
You could consider to prepopulate the table for all possibile questions / answers (NUM = 0).
At the end of every answer, you should update the NUM (+1) for ID_QUEST, ID_ANSWERS.
If you want register statistics for each session / user, you should add appropriate columns (ex. id_session, and/or user_id).
In this case you can't prepopulate table. And you can register only wrong answers.

Creating tables on registration in php

The question is not new in any way but it has a small twist to it.
My webpage is a membership page where users places bets. My idea is to create a new table for the users(with a naming convention like TABLE userBet+$userid) bets. User login information is already handled, my goal is now to save the bets of the user to a new table. A table which is created when users register. This will hopefully make score counting easier. Am I right or wrong? Could this be done in a better way? (Everything is done in PHP MySQL)
User registers -> Table for bets get created
"CREATE Table $userID ,id_bet, games, result, points"
And then matching this table against the correct result?
So again my questions: Is this a good way to do it? Is creating a table with the userID a smart thing to do?
EDIT
The bets is always 40 matches, which makes the tables Huge with columns and rows.
Should I make 40 Tables, one for each games instead? and put all users in there?
Am I right or wrong?
You are wrong. Dynamically altering your database schema will only make it harder to work with. There's no advantage you gain from doing so. You can do the same things by storing all bets within the same table, adding a column userid.
Posting as an answer due to author's request : )
Suggested database schema:
table matches:
id | name |
---------------
1 | A vs B |
table user_bets
id | user_id | match_id | points | result |
-------------------------------------------
1 | X | 1 | Y | Z |
Where match_id is related on matches.id
user_id = user.id
user_bets is only one table, containing all the info. No need of separate tables, as it was clear from the comments it's considered bad practice to alter the db schema via user input.

PHP/MySQL multiple votes

Hello I have voting system on my website but I would like to disable multiple voting from users. If the user votes he/she cannot vote again. Here is one solution which I have but is not good imo.
I created a column in users table: users_avoted where I would store the IDs of articles which he/she voted like tihs:
1|2|5|6
From this I would be able to check whether the user had already voted. But the thing is there will be a lot of articles so VARCHAR(255) will not be enough to store all of those IDs. Any other solutions?
Thanks
Don't denormalize it like that. Just have a two column table, userVotes, with a composite Key for UserID and ArticleID.
example data:
userid | articleid
1 1
1 2
1 67
2 1
This is better than something like
userID | articleID
1 1,2,67
Which is what it looks like you are suggesting. Please don't do this, and keep it normalized unless you want to do gymnastics every time you query. To elaborate, implementing what you suggested would defeat the purpose of using a RDBMS, in order to 'cheat' on one specific query.
You could instead make a table like:
users_avoted {
article_id,
user_id,
answer_id
}
Make a unique index out of article_id and user_id. That would only allow a single record to be input for that.
So, say they choose option 5 on article 2, and they are user 1.
Now, when you attempt to insert into the table:
INSERT INTO users_avoted VALUES (2, 1, 5)
You can't because the user already voted.
The benefit of this approach is that you don't have to check if they voted already first.
Store the votes in a table layed out like: id,username,voteid,vote for example.
Then when the user votes, check that table for matching rows.
For example:
if ($username == $dbusername && $voteid == $dbvoteid){
$disallowed = true;
}

Table design for a forum

To be clear, I'm not looking for someone to design an entire forum here, rather, I need some help determining how to relate a couple of tables, and whether or not these tables need to exist in the first place.
Basics of a forum
Topics
topic_id // Unique topic ID, AI, PK
topic_name // name of the topic
... etc
Topics
Posts in these topics (which is what this is here, a post
Replies to posts, which is what the responses below are (your responses that is)
Users
user_id // Unique ID of the user, PK, AI
user_name
user_pass
user_email
user_date
Posts
post_id // unique ID of post - PK, AI
post_content
... etc
I also want to include the ability to like / dislike a post, and for that reason I created a table post_ranking which looks as follows
id // Auto increment ID
post_id // Foreign key, refers to post.post_id
user_id // Foreign key, refers to user.user_id
vote_up // Whether or not the post was voted up (0 for down, 1 for up)
rank_date // date the ranking occured
The problem I've just run into is that I cannot figure out how to incorporate the replies into this table. The only option I've thought of so far would be to create a second table called reply_ranking - but wouldn't this be somewhat unorganized?
So, my question:
Should I create two separate tables for rankings (post_ranking , reply_ranking) or is there another way that I should be arranging the tables above which would avoid this problem in the first place?
Your post is not very clear, I can't understand if in the table Topics you have inside also posts in that topic and replies to that topic.
In this case I think that this is not the good way, you should have posts separated from topic data. Let me explain.
A forum is formed by:
// MAIN PAGE, showing avaible forums
// |
// SPECIFIC FORUM, that show the threads (or topics) inside
// |
// POSTS that show part of the post related to that thread.
//
// USER_CP -------------- ADMIN_CP
We need at least 4 tables (I'm not considering admin_cp).
these are:
// TOPICS:
// +---------------+---------+-------------+----------+----------+----------------+
// | ID, p.k. a.i. | TITLE | SUB_TITLE | AUTHOR | CLOSED | PARENT FORUM |
// +---------------+---------+-------------+----------+----------+----------------+
//
// These are very few basic field for the table. No reference about the posts here.
//
//
// FORUMS:
// +---------------+---------+-------------+--------------+
// | ID, p.k. a.i. | TITLE | SUB_TITLE | VISIBILITY |
// +---------------+---------+-------------+--------------+
//
// Almost clear, visibility is a value to determine if the forum is private (such are
// forums like: "Moderator rooms" or "Admin stuff"), protected (i.e. for non registered
// users, or if the forum is public.
//
//
// POSTS:
// +---------------+----------+-------+-----------+--------+---------+-------+- - -
// | ID, p.k. a.i. | TOPIC_ID | TITLE | SUB_TITLE | AUTHOR | MESSAGE | VOTES | ...
// +---------------+----------+-------+-----------+--------+---------+-------+- - -
//
// In Votes you have a integer number (positive o negative, no matter) with the total
// of the votes for this post (not useful if you fully use the table like).
//
// REPLIES
// +---------------+----------+---------+--------+---------+
// | ID, p.k. a.i. | TOPIC_ID | POST_ID | AUTHOR | MESSAGE |
// +---------------+----------+---------+--------+---------+
//
//
// USERS
// +---------------+------+------+------------+------+---------+- - - - -
// | ID, p.k. a.i. | NICK | PASS | PRIVILEGES | NAME | SURNAME | ETC..
// +---------------+------+------+------------+------+---------+- - - - -
//
// Privileges determinate if a user is admin, mod, super_mod or simple user
//
//
// LIKES
// +---------------+---------+---------+----------+----------+---------+------+
// | ID, p.k. a.i. | USER_ID | POST_ID | TOPIC_ID | REPLY_ID | UP_DOWN | DATE |
// +---------------+---------+---------+----------+----------+---------+------+
This is, in my opinion the structure you should use.
home page, show all the forums:
read the privileges of the user
read the forums data from the table WHERE visibility >= user_privileges
impaginate each forum with proper links.
Forum page, show all the topics (and moderators):
read the topics from the table WHERE parent_forum = forum_id
read moderators of this forum
impaginate topics with proper links
shows moderator at the bottom of the page.
Topic page, show all the messages.
read the topi data from the table.
the topic is also the first message!
read the posts from the table WHERE topic_id = current_topic_id
for each post read from the table "LIKES" WHERE post_id = selected_post
sum all the votes
impaginate the post in proper pages and proper votes.
User page:
read all the data, WHERE id = user_id_that_want
read from "LIKE" WHERE user_id = actual_user
you have all the likes/dislike the user sent. do what you want.
impaginate
With this table structure you can also use a StackOverflow similar way to consider votes, i.e. UPvotes are 0 for the voter, but downvote are -1 for the voter. For each post, you can read from the like table just using post_id, so you know how many votes have the post (up and down) and with this you can count also up vote +10 to the post creator, downvote -5 to post creator.
Only with an extra table that is likes.
You can have:
votes on a topic
votes on a post
votes on a reply
votes total (reply+post+topic) of the topic.
When you insert a topic you will add:
user_id
topic_id = topic id
post_id = -1 (this is not a post, is the topic!)
repl
y_id = -1 (as above)
when you insert a post:
user_id
topic_id = current topic
post_id = post_id
reply_id = -1 (this is not a a reply)
when you insert a reply
user_id
topic_id = current topic
post_id = current post
reply_id = the reply id.
This will not have id problem issues. because the three are separated.
If you call for all the answer of a specific topic and a specific post you will add:
WHERE topic_id = current, post_id = current
if you need the reply of a topic, just put post_id = -1
And so on.
No issues with the ids!
I think I have explained almost all. for any question, ask!
EDITED: something here and there
Another thing you can do is make a single rankings table, with a field indicating whether the upvote/downvote is for a post or a ranking. You will have to use a non unique generic "item_id" instead of post id or reply id, but you do get one table if this is important to you.
EDIT: Just realised the foreign key field will be non unique anyway, since you may have multiple votes for the same post; the point is post ids and reply ids can't be told apart.
This WILL make it harder to deal with querying the table. My recommendation is you go with your current plan and make two tables; it is the most semantic way you can organise your data.
I usually think like this:
One user has many posts (this means you'll need a users table and a posts table, and every post will have a user_id to signal who owns it.
For some relations, (for example, when you realize that A has many B and B has many A, that's what we can an n to n relationship), you'll need a third table; this might be what you are hinting at in your comment as to what the reply entity should be translated to in your database....
Feel free to commit errors... almost never you will end up with the exact same model you started with... many things we don't know we need until we do.

Rating System in PHP and MySQL

If we look at the stackoverflow website we have votes. But the question is what is the bestway to store who has voted and who has not. Lets also simplify this even more and say that we can only vote Up, and we can only Remove the Up vote.
I was thinking having the table to be in such form
question - Id(INT) | userId(INT) | title(TEXT) | vote(INT) | ratedBy(TEXT)
Thre rest is self explanitory but ratedBy is a Comma Seperated Id values of the Users.
I was thinking to read the ratedBy and compare it with the userId of the current logged in User. If he dosent exist in the ratedBy he can vote Up, otherwise he can remove his vote. Which in turn will remove the value from ratedBy
I think to make another table "vote" is better. The relationship between users and votes is n to n, therefore a new table should be created. It should be something like this:
question id (int) | user id (int) | permanent (bool) | timestamp (datetime)
Permanent field can be used to make votes stay after a given time, as SO does.
Other fields may be added according to desired features.
As each row will take at least 16B, you can have up to 250M rows in the table before the table uses 4GB (fat32 limit if there is one archive per table, which is the case for MyISAM and InnoDB).
Also, as Matthew Scharley points out in a comment, don't load all votes at once into memory (as fetching all the table in a resultset). You can always use LIMIT clause to narrow your query results.
A new table:
Article ID | User ID | Rating
Where Article ID and User ID make up the composite key, and rating would be 1, indicating upvote, -1 for a downvote and 0 for a removed vote (or just remove the row).
I believe your design won't be able to scale for large numbers of voters.
The typical thing to do is to create to tables
Table 1: question - Id(INT) | userId(INT) | title(TEXT)
Table 2: question - ID(INT) | vote(INT) | ratedBy(TEXT)
Then you can count the votes with a query like this:
SELECT t1.question_Id, t1.userId, t1.title, t2.sum(vote)
FROM table1 t1
LEFT JOIN table2 t2 ON t1.question_id = t2.question_id

Categories