aloo
aloo

Reputation: 5389

How to keep version history of datastore entities in Appengine

I'm storing an Entity A in my datastore on appengine. A has an id of type Long. I'd like to keep a history of all changes made to A's fields. What are the best practices to doing this type of version ing on entities? I'd prefer a solution that works well with subclasses of A and is as automatic as possible.

Thanks!

Upvotes: 9

Views: 3042

Answers (3)

Allan Veloso
Allan Veloso

Reputation: 6389

There are a lot of ways to do that.

If you want one way that do not require more classes in the data model, you can use parent attribute for write the versions and ancestor query with order to read the latest version.

Here is a example of how this could work in a wiki page using ndb.Model and webapp2 framework in Python GAE:

The model could be:

class WikiPage(ndb.Model):
    title = ndb.StringProperty(required = True)
    text = ndb.TextProperty(required = True)
    datetime = ndb.DateTimeProperty(auto_add_now = True)

The handle could be:

class Page(webapp2.RequestHandler):
    def get(self, path):
        # create the page key from the page id (in this case, the get request path)
        page_key = ndb.Key('WikiPage', path)

        # query for edited versions
        wikipage_edited = WikiPage.query(ancestor=page_key).order(-WikiPage.datetime).get()

        # check if wikipage have edited versions
        if wikipage_edited:
            wikipage = wikipage_edited

        # if not, get the original version
        else:
            wikipage = page_key.get()

        # some custom function to render the wikipage
        self.render(wikipage)

    def post(self):
        # you can pass some parameter that indicates the page_id being edited
        page_id = self.request.get('page_id')

        # check if page_id was sent
        if page_id:
            wikipage = WikiPage(parent = ndb.Key('WikiPage', page_id), 
                                title = self.request.get('new_title'), 
                                text = self.request.get('new_text'))

        # if page_id wasn't sent, it assumes that a new page is being created
        else:
            # some custom function that create a page id in the way you want
            page_id = self.create_a_page_id()
            wikipage = WikiPage(id = page_id, 
                                title = self.request.get('title'), 
                                text = self.request.get('text'))
        wikipage.put()

Upvotes: 0

Stefan
Stefan

Reputation: 754

You could create a linked list of entities, where each entity has two references: one to its previous version and one to the next version. You have to maintain those references yourself, of course. The most recent version of an entity will be the one without a reference to a next version (or an empty/null reference).

Depending on your use case you might also want to look at ways to only store the differences between two version of an entity (if changes are small and entities are large).

Upvotes: 2

Devraj
Devraj

Reputation: 3075

We are doing something similar for one of our AppEngine apps. The only efficient way we found was, have an Entity B that are your versions, and Entity A keeps a list of keys.

We then use ETags in our REST services to identify which version our client gets a copy of.

Upvotes: 0

Related Questions