NDB使用KeyProperty进行一对一建模

时间:2013-04-20 01:16:25

标签: google-app-engine database-design app-engine-ndb

我对ndb很新,但我已经明白我需要重新连接我脑中的某个区域来创建模型。我正在尝试创建一个简单的模型 - 只是为了理解如何设计一个ndb数据库 - 与一对一的关系:例如,用户和他的信息。经过大量搜索 - 找到了文档,但很难找到不同的例子 - 并进行了一些实验(以几种不同的方式进行建模和查询),这就是我找到的解决方案:

from google.appengine.ext import ndb

class Monster(ndb.Model):
    name = ndb.StringProperty()

    @classmethod
    def get_by_name(cls, name):
        return cls.query(cls.name == name).get()

    def get_info(self):
        return Info.query(Info.monster == self.key).get()

class Info(ndb.Model):
    monster = ndb.KeyProperty(kind='Monster')
    address = ndb.StringProperty()

a = Monster(name = "Dracula")
a.put()

b = Info(monster = a.key, address = "Transilvania")
b.put()

print Monster.get_by_name("Dracula").get_info().address

NDB不接受连接,因此我们想要的“连接”必须使用类方法和属性进行模拟。使用上面的系统,我可以通过第一个中的唯一属性(在本例中为“name” - 很容易到达第二个数据库(Info)中的属性 - 假设没有两个具有相同名称的怪物)。

但是,如果我要打印一个包含100个怪物名称和相应地址的列表,第二个数据库(信息)将被点击100次。

问题:有没有更好的方法对此进行建模以提高性能?

2 个答案:

答案 0 :(得分:1)

如果真的是一对一的关系,为什么要创建2个模型。鉴于你的例子,地址实体不能与任何怪物共享,所以为什么不把地址细节放在怪物中。

有些理由不这样做。

  1. 当您只需要一对夫妇时,地址可能变得很大,因此检索100个属性的效率会降低 - 尽管项目查询可能对此有所帮助。

  2. 你改变主意,想要看到所有生活在特兰西瓦尼亚的怪物 - 在这种情况下你会创建地址实体,而怪物将拥有指向地址的关键属性。当你弄清楚一些怪物可以生活在多个地方(狼人 - 伦敦,特兰西瓦尼亚,纽约;-)时,这显然会失败,在这种情况下,你要么在monstor中有一个重复的KeyProperty,要么是指向怪物的中间实体,地址。在你的情况下,我不认为怪物总体上有那么多记录的地址; - )

  3. 此外,如果您通过名称唯一识别怪物,则应考虑将名称存储为键的一部分。执行Monster.get_by_id(“dracula”)比按名称查询更快。

    正如我在评论中写的那样(很差)。如果1.以上持有并且它是真正的一对一关系。然后,我会在创建地址时创建Address作为子实体(Monster是键中的父/祖先)。这允许你,

    1. 允许其他实体指向地址,
    2. 如果您创建了一堆子实体,请使用单个实体获取它们 祖先查询)。 3如果你有怪物并且它拥有实体 再一次,这是一个祖先的查询。
    3. 如果你有一堆实体 应该只存在Monster实例存在但它们不存在 孩子们,那么你必须对所有实体类型进行查询 KeyProperty匹配密钥,如果这些实体不匹配 PolyModels,然后您必须为每个实体执行查询 type(并且知道你需要对给定的实体执行查询, 这涉及某种类型的注册表,或硬编码的东西)

答案 1 :(得分:0)

我怀疑您可能通过使用以下链接中描述的元素来实现您的尝试 看看“多个键或实体上的操作”“Expando模型”“模型挂钩”

https://developers.google.com/appengine/docs/python/ndb/entities

(这可能更多是评论而非答案)