I have a quite common design problem: I need to implement a history log (audit trail) for records in Google App Engine. The history log has to be structured, i.e I cannot join all changes into some free-form text and store in string field.
I've considered the following options for the history model and, after noticing performance issues in option #1, I've chosen to implement option #3. But have stil some doubts if this solution is efficient and scalable. For instance: is there a risk that performance will degrade significantly with increased number of dynamic properties in option #3?
Do you have some deeper knowledge on the pros/cons for each option or could suggest other audit trail design patterns applicable for Google App Engine DB characteristics?
fieldName
create history_fieldName_n
fields (where n=<0..N> is a number of history record)
fieldName
create a fieldName_history
list field
If I would have to choose I would go for option 1. The reads are as (if not more) performant for the other options. And all other options only have speed advantages under specific circumstances (small or very large sets of changes). It will also get you lots of flexibility (with more ease) like purging history after x days or query history across different model types. Make sure you create the history entities as a child of the changed entity in the same transaction to guarantee consistency. You could end up with one of these:
class HistoryEventFieldLevel(db.Model):
# parent, you don't have to define this
date = db.DateTime()
model = db.StringProperty()
property = db.StringProperty() # Name of changed property
action = db.EnumProperty(['insert', 'update', 'delete'])
old = db.PickleProperty() # Old value for field, empty on insert
new = db.PickleProperty() # New value for field, empty on delete
class HistoryEventModelLevel(db.Model):
# parent, you don't have to define this
date = db.DateTime()
model = db.StringProperty()
action = db.EnumProperty(['insert', 'update', 'delete'])
change = db.PickleProperty() # Dictionary with changed fields as keys and tuples (old value, new value) as values
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With