0

In my app, users earn a score and their details get stored in the datastore. When the user logs in, I want to show their rank among all users(basically how far away from the top score they are). So my solution was to sort the users' profiles in descending order the put the index+1 to the Profile model and run it in a cron.

However the cron fails. Any help or advise on a better way would be appreciated:

    from google.appengine.ext import db

    def universal_rank(self):
        users = Profile.all().filter('leaderboard =', l.key()).order('-score')
        rank = 0
        for user in users:
            rank = rank + 1
            user.rank = rank

        db.put(users)

I'm using webapp2

1

2 Answers 2

0

I believe you have the wrong syntax for the filter query. From the docs,

https://docs.djangoproject.com/en/1.8/topics/db/queries/

It looks like what you need is something like this..

users = Profile.objects.all().filter('leaderboard =', l.key()).order('-score')

Or, really, I don't think you need to the .all() in general.

users = Profile.objects.filter('leaderboard =', l.key()).order('-score')

I'm also not positive as to where you are getting l.key() but if you are getting all users, I think that you could just do

users = Profile.objects.all().order('-score')

5
  • Thanks but I'm using webapp2 that come bundled with GAE, not Django.
    – Orane
    Commented Apr 22, 2015 at 18:18
  • another quick comment, and maybe I'm interpreting what you are trying to do wrong, but aren't you reseting the rank to 1 for every user by doing this? Should you start with rank as user.rank? Commented Apr 22, 2015 at 18:23
  • Well the rank variable is outside of the for loop, so each iteration adds 1 to the rank. In better practice i should start rank = 1, then count onwards.
    – Orane
    Commented Apr 22, 2015 at 18:35
  • Hey bro, I solved it. I just changed from a bulk put --db.put(users) to individual puts -- user.put()
    – Orane
    Commented Apr 22, 2015 at 18:36
  • awesome, glad to hear you got it! and I didn't realize you wanted to rerank everytime, just thought you wanted to increase a counter, not start from scratch. Commented Apr 22, 2015 at 20:45
0

So it seems like the datastore can't bulk put over a certain limit. so i changed the code to as follows:

from google.appengine.ext import db

def universal_rank(self):
    users = Profile.all().filter('leaderboard =', l.key()).order('-score')
    rank = 0
    for user in users:
        rank = rank + 1
        user.rank = rank
        user.put()
3
  • This works but you should put in batches and async for improved performance.
    – Zig Mandel
    Commented Apr 23, 2015 at 3:27
  • Could you answer with an example?
    – Orane
    Commented Apr 23, 2015 at 3:28
  • Look at put_async. You can pass one or more entities. Find a safe number (say 20) to put at once like you were doing before. Then split all entities in groups of (20) and put_async each. You need only some more code to wait until commit and deal with fails.
    – Zig Mandel
    Commented Apr 23, 2015 at 3:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.