【问题标题】:GAE: from RDBMS to NDB problemsGAE:从 RDBMS 到 NDB 问题
【发布时间】:2013-05-21 14:20:19
【问题描述】:

我正在学习在 GAE 中工作。我已经阅读了很多论文,所有来自 Google 的 NDB 文档和一些问题。我已经习惯了 SQL,但是将过去 20 年的思维方式转变为 NoSQL 对我来说有点困难,而且这里给出的所有这些不同的解决方案都让我抓狂。

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

在传统的 SQL 中,我只创建从 VOTES 到 CHAPTERS 和 BOOKS 以及从 CHAPTERS 到 BOOKS 的外键。

我为我的模型这样做:

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. 获取特定章节和特定书籍的所有投票总和的正确方法是什么?

最后,我将展示一个包含我所有书籍的表格。在表格中,我想获得每本书的所有投票的总和。例如:

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

我如何获得这些信息,尤其是计票。

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

获取此类数据需要哪个 GQL?

提前致谢。

【问题讨论】:

    标签: python google-app-engine app-engine-ndb


    【解决方案1】:

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

    以下是我会做的一些不同的事情:

    • 看来您是在一个祖先下创建所有书籍。可怕的想法。在性能方面让你大吃一惊。除非您需要对一组不在您当前代码中的书籍进行一些事务性操作,否则这是不对的。

    • 从 Book.getChapters() 函数看来,您想让一本书成为一堆章节的祖先。这可能是对祖先的一个很好的利用。我没有看到您创建章节的代码,但请确保将相应的书指定为祖先。

    • 我只是将投票作为属性包含在书籍或章节中。无需将其设为需要发出额外查询的单独类型。

    • 如果每本书的章节数有限,我会考虑为章节使用 StructuredProperty。 StructuredProperties 本质上是父实体(书)中的结构化数据。您将受到 Book 实体的最大大小 (1MB) 的限制,但如果合适,它将为您节省进行额外查询的成本,因为无论如何您都不会在没有合适的书的情况下查询章节。

    【讨论】:

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