2013-05-21 50 views
2

我正在学GAE工作。我已经阅读了很多论文,Google的所有NDB文档以及这里的一些问题。我非常习惯SQL,但是我认为过去20年来NoSQL对我来说有点困难,所有这些不同的解决方案都给了我这里,让我发疯。GAE:从RDBMS到NDB问题

我有下一个简单的结构: 书比可以具有章和 章和可以具有票数 例如,书“前哨”可以有3个章节,每章将具有各自为0,图8和12票。

在传统的SQL中,我只是从VOTES到章节和书籍以及从章节到书籍的外键。

我这样做对我的模型:

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) 

好了,我的疑惑是:

  1. 是这种做法是否正确?
  2. 为了确保所有实体都使用祖先,我创建的函数bookKey()很适合拥有“虚拟祖先”?
  3. 我必须在Vote类中定义一本书和一章的参考,因为它是一个外键(就像我想的那样)?
  4. 是否定义了从书中检索章节的方式?我的意思是,在Chapter类中,函数byBook使用Book类中的函数。或者我必须避免使用其他实体的函数来获得更干净的代码?
  5. 我该如何检索所有章节的选票?
  6. 哪一种方法可以获得特定章节和特定书籍的所有选票总和?

最后,我将显示一张带有我所有书籍的表格。在表格中,我想得到每本书的所有选票的总和。例如:

名称|票选 Sentinel | 30票 女巫| 4票

我怎样才能得到这个信息,特别是计票。

然后,点击书名,我想要显示他所有的章节(那么当我必须在章模型上使用byBook函数时,我会提出这个章节吧?)。

哪一个是我需要获得这种数据的GQL?

在此先感谢。

回答

2

好的开始。 GAE的数据存储有点混乱。因为它是无模式的,所以我发现处理实体更像处理内存中的对象/数据结构,而不是处理数据库表。

这里有几件事我会做不同的:

  • 看样子你正在创建一个单一的祖先在你所有的书籍。可怕的想法。在性能方面让你过度。除非有一些交易操作,否则您需要对不在您当前代码中的一组书进行操作,这是不对的。

  • 从Book.getChapters()函数看来,您希望将书籍作为一组章节的祖先。这可能是一个祖先的良好用法。我没有看到创建章节的代码,但确保将适当的书籍指定为祖先。

  • 我只是简单地将一个投票作为一个属性放在书或章中。没有必要使它成为一种独立的类型,您需要发出额外的查询。

  • 如果每本书的章节数量有限,我会考虑使用StructuredProperty作为章节。 StructuredProperties本质上是一个父实体(Book)中的结构化数据。你会被Book实体的最大大小(1MB)所限制,但如果它合适的话,它会为你节省额外查询的成本,因为你不会在没有合适的书的情况下查询章节。

+0

说多数什么我可以说,但我想补充一点,如果你想获得总计和小计没有组由SQL选项,所以ü通过有环和自己添加的总数(我猜你可以有一个计算字段) – 2013-05-21 15:37:26

+0

谢谢,@dragonx。对于书籍祖先来说,我必须做什么?当我为书籍执行getAll()时,我需要指定一个祖先。如果每本书有不同的祖先,只会选择一本书,不是吗?当我创作第一章时,我将这本书作为祖先。在SQL中,投票显然必须是独立的,但是在NoSQL中可能不是。一个用户将进行投票,这会影响到章节,并且通过继承而产生一本书。如果我将它包含在两个实体中,我必须为每个投票管理双重工作,但可以。我将测试你最后一次关于StructuredProperties的建议。 NoSQL的硬路径。 ;) – Eagle

+0

祖先只在需要强一致性查询时才需要。如果你遗漏了祖先,你可以得到所有的书籍。缺点是你的查询最终是一致的。你需要决定最终一致的行为是否可以接受。如果这只是为了浏览,那很可能是。 – dragonx