Python GAE:从RDBMS到NDB问题

Python GAE:从RDBMS到NDB问题,python,google-app-engine,app-engine-ndb,Python,Google App Engine,App Engine Ndb,我正在学习在GAE工作。我已经阅读了很多论文,所有来自谷歌的NDB文档以及这里的一些问题。我非常习惯SQL,但将过去20年的思维方式转变为NoSQL对我来说有点困难,这里给出的所有不同解决方案都让我发疯 我有下一个简单的结构: 书不能有章节 可以投票的章节 例如,《哨兵》一书可以有3章,每章分别有0票、8票和12票 在传统的SQL中,我只是从投票到章节和书籍,从章节到书籍制作外键 我这样做是为了我的模型: class Book(ndb.Model): title = ndb.String

我正在学习在GAE工作。我已经阅读了很多论文,所有来自谷歌的NDB文档以及这里的一些问题。我非常习惯SQL,但将过去20年的思维方式转变为NoSQL对我来说有点困难,这里给出的所有不同解决方案都让我发疯

我有下一个简单的结构: 书不能有章节 可以投票的章节 例如,《哨兵》一书可以有3章,每章分别有0票、8票和12票

在传统的SQL中,我只是从投票到章节和书籍,从章节到书籍制作外键

我这样做是为了我的模型:

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)
那么我的疑问是:

  • 这种方法正确吗
  • 我创建的函数bookKey()最好有一个“虚拟祖先”,以确保所有实体都使用祖先
  • 我必须在投票课上为一本书和一个章节定义一个参考,因为它是外键(就像我想的那样)
  • 从一本书中检索章节的方法是否定义良好?我的意思是,在Chapter类中,函数byBook使用Book类中的函数。或者我必须避免使用来自其他实体的函数来获得更干净的代码
  • 我如何检索章节的所有投票
  • 哪一种是获得某一章节和某一本书所有票数总和的正确方法
  • 最后,我将显示一个包含所有书籍的表。在表格中,我想得到每本书的所有投票总数。例如:

    姓名|投票 哨兵| 30票 女巫投了4票

    我怎样才能得到这些信息,特别是统计的选票

    然后,点击书名,我想显示他的所有章节(我想那是我必须在章节模型上使用byBook功能的时候,对吗?)

    我需要哪个GQL来获取此类数据


    提前谢谢。

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

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

    • 看起来你是在一个单一的祖先下创作你所有的书。糟糕的主意。就性能而言,这让你大吃一惊。除非您需要对一组不在当前代码中的书籍执行某些事务操作,否则这是不对的

    • 从Book.getChapters()函数中,似乎您希望将一本书作为一组章节的祖先。这可能是对祖先的一种很好的利用。我看不到创建章节的代码,但请确保将适当的书籍指定为祖先

    • 我只想在一本书或一章中加入投票作为属性。没有必要让它成为一种单独的类型,您需要对其发出额外的查询

    • >P>如果每本书的篇章数量有限,我会考虑使用章节的结构属性。StructuredProperties本质上是父实体(书本)中的结构化数据。您可能会受到图书实体的最大大小(1MB)的限制,但如果适合,它将为您节省额外查询的成本,因为如果没有合适的图书,您将无法查询章节


    已经说出了我本可以说的大部分内容,但我可能要补充的是,如果您想获得总计和小计,没有“按sql分组”选项,因此您必须自己循环并添加总计(我想您可以有一个计算字段),谢谢,@dragonx。那么,对于书的祖先,我必须做什么呢?当我为书籍执行getAll()时,我需要指定一个祖先。如果每本书都有不同的祖先,那么只会选择一本书,不是吗?当我创建一个章节时,我会把这本书作为祖先传下去。在SQL中,投票显然必须是独立的,但在NoSQL中可能不是。一个用户将进行投票,这将影响一个章节,并通过继承影响一本书。如果我将其包括在两个实体中,我必须为每次投票管理双重工作,但可以。我将测试您关于StructuredProperties的最后一个建议。这是NoSQL的硬路径只有在需要强一致性查询时,祖先才是必需的。如果你不考虑祖先,你可以得到所有的书。缺点是您的查询最终是一致的。你需要决定最终一致的行为是否可以接受。如果这只是为了浏览,那么很可能是。就投票而言,这不是SQL对NoSQL的真正较量。如果您有额外的投票数据,比如谁投票,您可能需要一个投票表。但在您给出的示例中,每次查看一本书或一个章节实体时,必须对所有投票进行求和是低效的。在投票中更新它的处理更少,那么无论何时有人查看你的页面,你都不需要再次重新计算投票。在一本书的一个章节中,将所有投票数相加需要更多的工作,但实际上,这是一个简单的循环。因此,对根实体(本例中为书)使用唯一的祖先对于性能问题是一个坏主意,最好是最终保持一致(我想这意味着可以不读取仍在保存的数据,这是我保存一本没有祖先的书时发生的情况)。对于投票,我已经将问题总结为一个容易理解的问题,但事实上,我将有4种投票(有一种属性我没有包括在内),所以我想这将改变规则,并且有必要将其纳入他们自己的实体中。但这是真的,如果is单独一人在书中更有意义的话