Question

I have a voting system for articles. Articles are stored in 'stories' table and all votes are stored in 'votes' table. id in 'stories' table is equal to item_name in 'votes' table (therefore each vote is related to article with item_name).

I want to make it so when sum of votes gets to 10 it updates 'showing' field in 'stories' table to value of "1".

I was thinking about setting up a cron job that runs every hour to check all posts that have a showing = 0. If showing = 0 than it will sum up votes related to that article and set showing = 1 if sum of votes >= 10. I'm not sure if it is efficient as it might take up a lot of server resources, not sure.

So could anyone suggest a cron job that could do the task?

Here is my database structure:

Stories table

enter image description here


Votes table

enter image description here


Edit:

For example this row from 'stories' table:

id| 12
st_auth | author name
st_date | story date
st_title| story title
st_category| story category
st_body| story body
showing| 0 for unaproved and 1 for approved

This row is related to this one from 'votes' table

id| 83 item_name| 12 (id of article) vote_value| 1 for upvote -1 for downvote ...

Was it helpful?

Solution

Couple of things:

  1. Why did you name the column item_name in the votes table, when it is actually the id of the article table? I would recommend making this a match on the article table in that it is an int(11) vs a var_char(255). Also, you should add a foreign key constraint to the votes table, so if an article is ever deleted, you don't orphan a row in the votes table.

  2. Why is the vote_value column an int(11)? If it can only be two states (1, or -1) you can do a tinyint(1) signed (for the -1).

  3. The ip column in the votes table is a bit concerning. If you are regulating 'unique' votes by ip, did you account for proxy ips? Something like this should be handled at the account level, so several users from the same proxy IP can issue individual votes.

  4. I wouldn't do a cronjob for determining whether the showing column should be flagged 0 or 1. Rather, I would issue a count every time a vote was cast against the article. So if someone up-voted or down-voted, calculate the new value of the story, and store it in cache for future reads.

OTHER TIPS

Using this query, you get a list of all articles plus a column containing the count of associated votes.

SELECT s.*, SUM(v.vote_value) AS votes_total
FROM stories AS s INNER JOIN votes AS v
ON v.item_name = s.id
GROUP BY v.vote

This way, you can create a view from which you can filter on votes_total > 10, without need of the cron job.

Or you can use it as a normal query, something like this:

SELECT * FROM (
  SELECT s.*, SUM(v.vote_value) AS votes_total
  FROM stories AS s INNER JOIN votes AS v
  ON v.item_name = s.id
  GROUP BY v.vote
) WHERE votes_total > 10;

I would use a trigger (insert trigger) and handle your logic there (in the database itself)? This would remove the poll code altogether (cron job). I would also keep your foreign key (in VOTES) the same (at least the type) as the primary key (in STORIES)?

Using a trigger instead of polling will be much cleaner in the long run.

You don't specify your database, but in TSQL (for SQL Server) it could be close to this

CREATE TRIGGER myTrigger 
ON VOTES
FOR INSERT
AS

DECLARE @I INT --HOLDS COUNT OF VOTES

DECLARE @IN VARCHAR(255) --HOLDS FK ID FOR LOOKUP INTO STORIES IF UPDATE REQUIRED

SELECT @IN = ITEM_NAME FROM INSERTED

SELECT @I = COUNT(*) FROM VOTES WHERE ITEM_NAME = @IN

IF (@I >= 10)

BEGIN

  UPDATE STORIES SET SHOWING = 1 WHERE ID = @IN --This is why your PK/FK should be refactored

END
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top