Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maintain uniqueness of a property in the NDB database

An NDB model contains two properties: email and password. How to avoid adding to the database two records with the same email? NDB doesn't have UNIQUE option for a property, like relational databases do.

Checking that new email is not in the database before adding—won't satisfy me, because two parallel processes can both simultaneously do the checking and each add the same email.

I'm not sure that transactions can help here, I am under this impression after reading some of the manuals. Maybe the synchronous transactions? Does it mean one at a time?

like image 591
Graduate Avatar asked Aug 19 '13 11:08

Graduate


3 Answers

Create the key of the entity by email, then use get_or_insert to check if exists.

Also read about keys , entities. and models

#ADD
key_a = ndb.Key(Person, email);
person = Person(key=key_a)
person.put()

#Insert unique    
a = Person.get_or_insert(email)

or if you want to just check

#ADD
key_a = ndb.Key(Person, email);
person = Person(key=key_a)
person.put()

#Check if it's added
new_key_a =ndb.Key(Person, email);
a = new_key_a.get()
if a is not None:
    return

Take care. Changing email will be really difficult (need to create new entry and copy all entries to new parent).

For that thing maybe you need to store the email, in another entity and have the User be the parent of that.

Another way is to use Transactions and check the email property. Transaction's work in the way: First that commits is the First that wins. A concept which means that if 2 users check for email only the first (lucky) one will succeed, thus your data will be consistent.

like image 98
Jimmy Kane Avatar answered Nov 16 '22 01:11

Jimmy Kane


I also ran into this problem, and the solution above didn't solve my problem:

  • making it a key was unacceptable in my case (i need the property to be changeable in the future)
  • using transactions on the email property doesn't work AFAIK (you can't do queries on non-key names inside transactions, so you can't check whether the e-mail already exists).

I ended up creating a separate model with no properties, and the unique property (email address) as the key name. In the main model, I store a reference to the email model (instead of storing the email as a string). Then, I can make 'change_email' a transaction that checks for uniqueness by looking up the email by key.

like image 24
Remko Avatar answered Nov 16 '22 03:11

Remko


Maybe you are looking for the webapp2-authentication module, that can handle this for you. It can be imported like this import webapp2_extras.appengine.auth.models. Look here for a complete example.

like image 43
Hinrich Avatar answered Nov 16 '22 03:11

Hinrich