I'm learning to work in GAE. I'm so used to SQL, but transform my way of think the last 20 years to NoSQL is a little hard for me.I have the next simple structure:BOOKS than can have CHAPTERSCHAPTERS that can have VOTESIn a traditional SQL I just make foreign keys from VOTES to CHAPTERS, and from it to BOOKS.I do this for my models in Datastore:class Book(db.Model):    title = db.StringProperty(required=True)    author = db.StringProperty(required=True)    created = db.DateTimeProperty(auto_now_add=True)    # Get all the Chapters for a book    def getChapters(self):        key = self.chapterMemkey()        chapters = memcache.get(key)        if chapters is None:            logging.info('DB access for key %s.', key)            chapters = Chapter.all().ancestor(self).order(number).fetch(100)            if not memcache.set(key, chapters, 300):                logging.error('Memcache set failed for Chapters.')        else:            logging.info('Memcache for key %s.', key)        return chaptersclass Chapter(db.Model):     All chapters that a book have     title = db.StringProperty(required=True)    number = db.IntegerProperty(default=1)    created = db.DateTimeProperty(auto_now_add=True)    book = db.ReferenceProperty(Book,                                required=True,                                collection_name='chapters')    # Search by Book (parent)    @classmethod    def byBook(cls, book, limit=100):        chapter = book.getChapters()        return chapter    # Search by id    @classmethod    def byId(cls, id, book):        return Chapter.get_by_id(long(id), parent=book)class Vote(db.Model):     All votes that a book-chapter have     chapterNumber = db.IntegerProperty(required=True)    option = db.IntegerProperty(default=1)    value = db.IntegerProperty(default=1)    book = db.ReferenceProperty(Book,                                required=True,                                collection_name='book_votes')    chapter = db.ReferenceProperty(Chapter,                                   required=True,                                   collection_name='chapter_votes')    # --------------------------    # ClassMethods for the class    # --------------------------    # Search by Book (parent)    @classmethod    def byBook(cls, book, limit=100):        vote = book.getVotes()        return vote    # Search by id    @classmethod    def byId(cls, id, book):        return Vote.get_by_id(long(id), parent=book)Well, my doubts are:Is this approach correct?Must I define in the Vote class a reference for a book and for a chapter, as it was a foreign keys (just like I think I've done)?Is well defined the way to retrieve the chapters from a book? I mean, in the Chapter class the function byBook uses a function from the Book class.In the Vote class, I also define the byBook function but, must I define another byChapter function with similar behaviour than the myBook function? I mean something like that:@classmethoddef byChapter(cls, chapter, limit=100):    vote = chapter.getVotes()    return voteAre the parents well-defined for Votes (book) or must Chapter instead be a Book? The votes are for the chapters, but a chapter belongs to book.Which are the right ways to get the sum of all the votes for a specific chapter and for specific book?
Defining book models in GAE
python;google app engine
This depends on a few things (keep reading).Not necessarily. This is a question of optimization. You could fetch a vote's book by using Chapter as an intermediary (vote.getChapter().getBook()), but this would obviously require sequential trips to the database - one to get the vote, followed by one to get the chapter, and finally one to get the book. Do you plan on fetching a book for a vote frequently? If so, save some resources and stick with what you've got.From a dependency standpoint, this seems counterintuitive, but since a chapter cannot exist without a book (can it?), I would say this is fine and simply a matter of preference. This always seems awkward to me as well, so maybe someone else can provide more info.You can, again, this is a question of optimization and convenience. When you have questions like this, ask yourself, will I really need this?. If the answer is no, or you're unsure, leave it out; you can always add it later if your needs change (the relations are setup correctly to do the joins, right?).See above.I would provide a Chapter.getVotesSum() and/or Book.getVotesSum(). These methods would include GQL queries to aggregate the appropriate rows from the votes table into a sum.(Sorry if I'm missing something, I don't use GAE)