How to model a Leaderboard

Here is something to get you started in Python:

from operator import itemgetter

import fdb
from fdb.tuple import pack
from fdb.tuple import unpack


fdb.api_version(510)


@fdb.transactional
def get_score(tr, user):
    """Return the score of the user.

    Add the user to the leaderboard if they are not already there

    """
    user_key = pack(('scores', user))
    score = tr.get(user_key)
    if score == None:
        # init the score at zero
        score = 0
        tr.set(user_key, pack((score,)))
        # Also store the user in the leaderboard.
        # Here the value is empty and the full data is encoded
        # in the key in order to make each key unique and keep
        # the leaderboard sorted.
        tr.set(pack(('leaderboard', score, user)), b'')
    else:
        score = unpack(score)[0]
    return score


@fdb.transactional
def add(tr, user, increment=1):
    """Add INCREMENT to USER score.

    Return the new score of the user"""
    score = get_score(tr, user)
    total = score + increment
    # update the user's score...
    user_key = pack(('scores', user))
    tr.set(user_key, pack((total,)))
    # ...and the leaderboard
    tr.clear(pack(('leaderboard', score, user)))
    tr.set(pack(('leaderboard', total, user)), b'')
    return total


@fdb.transactional
def top(tr, count=3):
    out = dict()
    # iterate over the whole 'leaderboard' namespace in reverse order
    iterator = tr.get_range_startswith(pack(('leaderboard',)), reverse=True)
    for key, _ in iterator:
        _, score, user = unpack(key)
        if score in out.keys():
            out[score].append(user)
        elif len(out.keys()) == count:
            break
        else:
            out[score] = [user]

    # output a sorted dict (python >= 3.6)
    return dict(sorted(out.items(), key=itemgetter(0), reverse=True))

Here is an example REPL run:

In [1]: import fdb

In [2]: import leaderboard

In [3]: db = fdb.open()

In [4]: 

In [4]: leaderboard.add(db, 'amirouche', 42)
Out[4]: 42

In [5]: leaderboard.top(db)
Out[5]: {0: ['nitu'], 42: ['amirouche']}

In [6]: leaderboard.add(db, 'nitu', 42)
Out[6]: 42

In [7]: leaderboard.top(db)
Out[7]: {42: ['nitu', 'amirouche']}

In [8]: leaderboard.add(db, 'amirouche', 42)
Out[8]: 84

In [9]: leaderboard.top(db)
Out[9]: {42: ['nitu'], 84: ['amirouche']}

Feel free to ask question, there is no stupid question, especially at this point.

Also, I’ve been answering question about how to create applications ontop key-value stores on stackoverflow, see “Find by value on leveldb” and “Key Value Store in NoSQL Database Systems”.

BTW, before some ask the question, I don’t think it’s worth learning wiredtiger or leveldb or lmdb at this point (except maybe if you plan to do event sourcing like SkuVault).

edit: copy/paste failure