TipTop
TipTop

Reputation: 143

App Engine datastore: ID auto increment with NDB

I'm modelling data, which IDs should be with auto increment. Actually, I've made working model, but need some advise from datastore guru.

There is my code for ID generation:

class AutoIncrementModel(ndb.Model):
  entity_id = ndb.IntegerProperty('eID')
  def _pre_put_hook(self):
    if self.key and self.key.id(): return
    latest = self.__class__.query().order(-self.__class__.entity_id).get()
    self.entity_id = latest and latest.entity_id + 1 or 1
    while self.__class__.get_by_id(self.entity_id): self.entity_id += 1
    self.key = ndb.Key(self.__class__.__name__, self.entity_id, parent=self.key and self.key.parent() or None)
    self.put()

This code generates straightforward IDs, but I'm quite not sure is it good enough.

UPD: This code fails. Several entities can be written with same key and data can be overwritten.

№1. Can it cause problem with data loss? "While loop" preserves app from generating ID. But I'm not sure there is no possibility for data to be overwritten.

№2. May transaction like this make saving better?

  def _pre_put_hook(self):
    def callback():
      while self.__class__.get_by_id(self.entity_id): self.entity_id += 1
      self.key = ndb.Key(self.__class__.__name__, self.entity_id, parent=self.key and self.key.parent() or None)
      self.put()
    if self.key and self.key.id(): return
    latest = self.__class__.query().order(-self.__class__.entity_id).get()
    self.entity_id = latest and latest.entity_id + 1 or 1
    ndb.transaction(callback, xg=True)

UPD: Transaction helps to avoid data loss. This code seems to work much better than first example.

№3. Is there a way to get max ID from group of entities without extra field for index?

Upvotes: 1

Views: 5910

Answers (2)

Harold Sarmiento
Harold Sarmiento

Reputation: 127

does not have sense to order by "self.class.entity_id" field beacuse this field is an unique identifier, never has an incremental value, no has sense to add neither.

Upvotes: 0

max
max

Reputation: 29983

Basically this can't be done. You need an external counter "singleton" and should add sharing for performance should you need more than about one write per second. See How to implement "autoincrement" on Google AppEngine for an discussion of the options.

Upvotes: 3

Related Questions