The context of my question is an educational project where an application deployed on Google App Engine sends questions to a large number of users that submit answers. Questions are translated into a number of languages and each user can decide the language to be used.
Each question is associated to a number of answers (up to 4) and only one of them is correct. The question length is restricted to 200 characters and the answer length to 2 or 3 words.
I'm also interested in storing how many times questions are sent and how many times answers are picked by the users.
Until I was aware of the existence of Structured Properties, this was my design:
class Question (ndb.Model):
Language = ndb.StringProperty(required = True, default = 'en')
Text = ndb.StringProperty(required = True, indexed = False)
class QuestionTranslation (ndb.Model):
Question = ndb.KeyProperty(Question, required = True)
Language = ndb.StringProperty(required = True)
Translation = ndb.StringProperty(required = True, indexed = False)
class QuestionStats (ndb.Model):
Question = ndb.KeyProperty(Question, required = True)
TimesUsed = ndb.IntegerProperty(default = 0)
class Answer (ndb.Model):
Question = ndb.KeyProperty(Question, required = True)
Language = ndb.StringProperty(required = True, default = 'en')
Text = ndb.StringProperty(required = True, indexed = False)
IsCorrect = ndb.BooleanProperty(required = True, default = False)
class AnswerTranslation (ndb.Model):
Answer = ndb.KeyProperty(Answer, required = True)
Language = ndb.StringProperty(required = True, default = 'es')
Translation = ndb.StringProperty(required = True, indexed = False)
class AnswerStats (ndb.Model):
Answer = ndb.KeyProperty(Answer, required = True)
TimesPicked = ndb.IntegerProperty(default = 0)
However, this design doesn't feel right to me because I'm basically repeating the code in QuestionTranslation and AnswerTranslation and this approach doesn't scale well when including new entities whose content must be translated to multiple languages as well.
Furthermore, now I know that using a StructuredProperty in this case has an important advantage over a KeyProperty since the number of queries can be reduced when, for instance, obtaining the answers of a question.
This is my current design:
class Translation (ndb.Model):
Language = ndb.StringProperty(required = True, default = 'en')
Text = ndb.StringProperty(required = True, indexed = False)
class Answer (ndb.Model):
Translations = ndb.StructuredProperty(Translation, repeated = True)
IsCorrect = ndb.BooleanProperty(required = True, default = False)
TimesPicked = ndb.IntegerProperty(default = 0)
class Question (ndb.Model):
Translations = ndb.StructuredProperty(Translation, repeated = True)
Answers = ndb.LocalStructuredProperty(Answer, repeated = True)
TimesUsed = ndb.IntegerProperty(default = 0)
It's much simpler and Translation is the only entity required for content translation. Nevertheless, I had to adopt the work-around mentioned in the GAE documentation [1] so that the StructuredProperty Answers that is repeated in Question can contain another StructuredProperty, Translations, which is also repeated in Answer. On the other hand, the stats (e.g. number of times a question is used) are integrated in the main entities.
Am I in the right direction? Do you suggest any alternatives that scale well and help me reduce the number of queries?
Thanks a lot.
[1] https://developers.google.com/appengine/docs/python/ndb/properties#structured