Reputation: 1074
I'm learning to work in GAE. I've read a lot of papers, all NDB docs from Google and asome questions here. I'm so used to SQL, but transform my way of think the last 20 years to NoSQL is a little hard for me, and all those different solutions gave here, drives me crazy.
I have the next simple structure: BOOKS than can have CHAPTERS CHAPTERS that can have VOTES For example, Book "Sentinel" can have 3 chapters, and every chapter will have 0, 8 and 12 votes each.
In a traditional SQL I just make foreign keys from VOTES to CHAPTERS and BOOKS, and from CHAPTERS to BOOKS.
I do this for my models:
class Book(ndb.Model):
title = ndb.StringProperty(required=True)
author = ndb.StringProperty(required=True)
created = ndb.DateTimeProperty(auto_now_add=True)
# Define a default ancestor for all the books
@staticmethod
def bookKey(group='books'):
return ndb.Key(Book, group)
# Search all
@classmethod
def getAll(cls):
q = Book.query(ancestor=cls.bookKey())
q = q.order(Book.title)
books = q.fetch(100)
return books
@classmethod
def byId(cls, id):
book = Book.get_by_id(long(id), cls.bookKey())
# Get all the Chapters for a book
def getChapters(self):
chapters = Chapter.query(ancestor=self).order(Chapter.number).fetch(100)
return chapters
class Chapter(ndb.Model):
""" All chapters that a book have """
title = ndb.StringProperty(required=True)
number = ndb.IntegerProperty(default=1)
created = ndb.DateTimeProperty(auto_now_add=True)
book = ndb.KeyProperty(kind=Book)
# 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(ndb.Model):
""" All votes that a book-chapter have """
value = ndb.IntegerProperty(default=1)
book = ndb.KeyProperty(kind=Book)
chapter = ndb.KeyProperty(kind=Chapter)
Well, my doubts are:
Finally, I will display a single table with all my books. In the table I want to have the sum of all the votes for each book. For example:
Name | Votes Sentinel | 30 votes The witch | 4 votes
How can I get this info, especifically, the counted votes.
Then, clicking on the book name, I want to show all his chapters (I supose that is then when I must use the byBook function on Chapter model, right?).
Which is the GQL I need to obtain this kind of data?
Thanks in advance.
Upvotes: 2
Views: 315
Reputation: 15143
Good start. GAE's datastore is kinda confusing. Because it's schemaless, I've found that dealing with entities is much more akin to dealing with objects/data structures in memory than dealing with database tables.
Here's a few things I'd do differently:
It appears you are creating all your books under a single ancestor. Terrible idea. Screws you over in terms of performance. Unless there is some transactional operation you need to do on a group of books that's not in your current code, this is not right.
From the Book.getChapters() function it appears that you want to make a book the ancestor of a bunch of chapters. This is probably a good use of an ancestor. I don't see the code where you create chapters, but make sure the appropriate book is specified as the ancestor.
I'd simply include a vote as an attribute inside a book or chapter. There's no need to make it a separate kind that you need to issue extra queries on.
If the number of chapters per book would be limited, I'd consider using a StructuredProperty for the chapters. StructuredProperties are essentially structured data within a parent entity (Book). You'd be limited by the maximum size of the Book entity (1MB), but if it fits, it'll save you the cost of doing extra queries, since you wouldn't be querying on chapters without the appropriate book anyways.
Upvotes: 2