Query database starting from a certain id - mysql

My app's functionality is like Tinder. I will go through the work flow.
App loads 10 Hunts (like tinder profiles)
User accepts or rejects it
Once user accepts or reject, hunt is removed (marked as seen so that it doesnt come back again )
When Hunts count become 2 , app loads next 10 hunts. ( This is not second page as seen hunts are already removed )
Here is the tricky part. When it queries database again, the hunt would have the 2 hunts which user hasnt yet accepted or rejected. To avoid duplication I avoid first 2 hunts from the response. But problem occurs if the query is run after one more accept or reject. I would remove 2 hunts expecting normal behavior but this would remove eliminate one hunt which is not a duplicate.
What would a best solution would be to get all the hunts which comes after a certain id.I can use WHERE NOT ID IN by passing the ids. But I would like to know if there is a better solution as I see this would be a pretty common scenario .
I hope I made myself very clear.
The solutions which I have thought of but not really liked
Pass ids of the 2 hunts back and exclude them in the results
Remove duplicates from hunts once I receive response back in my app
All suggestions are welcome. I m using Rails so active record solutions are also welcome.

It may be wise to add a status column with values 0,1,2 for unseen, rejected, accepted.
Then, when your user accepts / rejects each item, update that column.
To get the oldest (lowest-id-value) chunk of items for a user, use something like this.
WHERE user=whatever AND status=0
ORDER BY id
LIMIT 10
Build an index on (user, status, id), and MySQL can optimize this query.

Related

Whats the best way to implement this use in my database?

I have a central database containing millions of IDs. And I have a group of users (50-100 users), all being able to request extraction of IDs from this big database.
Atm what I do is when a user sends a GET request, I SELECT 100 ids then update them with the flag USED and return the 100. The problem is, if I get too many requests at the same time, multiple users will receive the same ids (because I dont lock the db when doing select and then update)
If I lock the database my problem will be solved, but it will also be slower.
What other alternative I have?
Thanks!
Look ahead another step... What if a "user" gets 100 rows, then keels over dead. Do you have a way to release those 100 for someone else to work on?
You need an extra table to handle "check out" and "check in". Also, use that table to keep track of the "next" 100 to assign to a user.
When a user checks out the 100, a record of that is stored in the table, together with a timestamp and "who" checked them out. If they don't "check them back in within, say, an hour, then you assign that 100 to another user.
Back on something more mundane... How to pick 100. If there is an auto_increment id with no gaps, then use simple math to chunk up the list. If there are a lot of gaps, then use SELECT id FROM tbl WHERE id > $leftoff ORDER BY id LIMIT 100, 1 to get the end of the next 100.
If each user has their own key, you could pull from the millions of IDs starting from their key*10000. For example, user #9 would first get IDs #90000 to #90099, then #90100 to #90199 next time.
You could set the IDs as "Used" before they get sent back, so one user requesting IDs multiple times will never get duplicates. This needn't lock the database for other users.
If they don't request keys more than 100 times before the database can update, this should avoid collisions. You might need to add logic to allow users who request often not to run out, like by having a pool of IDs that can repopulate their supply, but that depends on particulars that aren't clear from the original question.

Does pymysql's lastrowid function work properly in cases of multiple users inserting into DB?

I have 2 tables in my DB purchase order and lines. Every order can have multiple lines(one line for each part ordered). I am developing an application where an order will first be created. Need to get the ID of this order and then insert lines later on(as the user adds the parts). How can I ensure ther correct value of order ID is fetched?
I cant understand what you exactly want but you should search about ORM its maybe can help you.

How to prevent AJAX request hack?

I have a MySQL table which stores scores of the users. Every time a user answer a question correctly, I add his or her score by one using AJAX request. The request sends just an integer number which is the id of the question.
My Question is: How to prevent fake AJAX requests?
As it is just an integer number I can't check if it is a fake request or not. So the only solution I come up with is to add an extra column to my table, named "yesterday_score", as its name describe it is a column that change at time 00:00 and save users score. If a user add his score more than 300 in a day, I assume it is a hack, and I prevent it.
Check then answer with your back end to increment, not with the front end.
Never trust user input it the rule number one!
Rather than sending the number to the database you can use the language your database uses to update the number. So in MySQL
UPDATE users SET score = score + 1 WHERE user_id = 12
user_id can be verified by comparing it with the session or something of the sort. Be sure to use prepared statements too.
I read a lot of related pages, some user suggested some kinds of solutions like: "If a user hits 10 headshots in 10ms then you kick him. Write a clever cheat detection algorithm."
And there is an answer in same question:
There is no way to avoid forged requests in this case, as the client
browser already has everything necessary to make the request; it is
only a matter of some debugging for a malicious user to figure out how
to make arbitrary requests to your backend, and probably even using
your own code to make it easier. You don't need "cryptographic
tricks", you need only obfuscation, and that will only make forging a
bit inconvenient, but still not impossible.
in this page :
How to block external http requests? (securing AJAX calls)
I might also use PHPIDS. But for know I think I will stick with my solution, I add another column and hold the user's "yesterday-score" and if the user get more than 100 score today I will know he is defenetly cheating so I won't increment extra score.
Add a hidden field to form, and put in - md5(session_id())
if answer is correct - session_regenerate_id();

Update statistic counter or just count(*) - Perfomance

What is the faster/better way to keep track on statistical data in a message board?
-> number of posts/topics
Update a column like 'number_of_posts' for each incoming post or after a post gets deleted.
Or just count(*) on the posts matching a topicId?
Just use count(*) - it's built into the database. It's well tested, and already written.
Having a special column to do this for you means you need to write the code to manage it, keep it in sync with the actual value (on adds and deletes). Why make more work for yourself?

How to save game-progress in a MySQL database

I am developing a website that is a kind of game. The users' progress is saved in a MySQL-database.
I want to go about this by having a table saves with a column save (ID) and a column progress, where progress is of datatype text. When the user starts out, progress is set to (e.g.) '0'. If he proceeds to level 1, progress is set to '0#1', level two makes it '0#1#2'. The order of levels is free and I want to save it. So progress could be '0#4#2#15' and so on.
Is this a good way to do this? I have no experience with SQL and I don't want to do something incredibly stupid. I've read so much confusing info about tables, foreign keys and whatnot...
I want to thank you for your time reading this and I'm looking forward to answers.
Ryan
Answer to your Question 1
I would not approach your problem this way. I would create 3 tables: a Levels table (primary key of 'levelKey'), a Users table (primary key of 'userKey') and a User_Levels table with a composite key of 'levelKey' and 'userKey'. When a user completes a level, just insert into the User_Levels table. Then to see if a user has completed a level is a simple select:
SELECT 'a' FROM User_Levels WHERE userKey = ? AND levelKey = ?
If the number of rows is > 0, the user has completed the level
As for Question 2, I'd say the amount of queries is not the problem. After all, you are writing data to the database, not accessing it. Personally, I would send a "save" to the database, whenever a user actually completes a level.
watcher has posted a good approach for splitting up the levels and users into different tables. The sequence of progress can be seen from the order the progress gets logged into the User_Levels, so no need to store something like 1#3#4#9
You will probably want to send the save in the background with ajax, so you don't interrupt the game play. Look into jQuery's $.post method, for example. Or if your game is in flash, you can use a URLRequest.
About your first question, if the game / levels are non-linear personally I would take a different approach; I would simply add a table which contains a column for the user ID and a column for the level completed. So if user 1 has completed levels 0, 4 and 7, my table would have 3 rows:
UID levels_completed
1 0
1 4
1 7
About your other questions, you can use javascript events and ajax to detect the closing of the page but I would not rely on that; I would just run the queries whenever needed. And if your session is destroyed, you are already too late...