Appengine ndb - How to ensure unique username and email without ancestors?

89 Views Asked by At

In my Appengine (using ndb) application I store users and both username and email need to be unique. I also need to be able to update progress (save level if higher than previously stored level), change email and pw and delete account.

I noticed that it is not possible to query without ancestors in a transaction. But creating an ancestor is NOT a solution since that would limit the number of writes to 1 per second which is not OK if the app gets popular. So I need another solution.

Is it possible to use the Key? Yes, but that only makes the username unique, how can I make sure noone is reusing the email for another account?

1

There are 1 best solutions below

0
On BEST ANSWER

You should be able to use a cross group transaction for this along with an entity that exists solely for reserving email addresses.

For your User entity, you could use the username as the key name. When creating a user, you also create an EmailReservation entity that has the user's email address as a key name.

You then use a cross-group transaction to create a new user:

@ndb.transactional(xg=True)
def create_user(user_name, email):
    user = User.get_by_id(user_name)
    email_reservation = EmailReservation.get_by_id(email)
    if user or email_reservation:
        # Either the user_name or email is already in use so stop
        return None
    # Create the user and reserve the email address so others can't use it
    user = User(id=user_name)
    email_reservation = EmailReservation(id=email)
    ndb.put_multi(user, email_reservation)
    return user