ndb建模一对多:重复KeyProperty与外键的优点

时间:2012-12-18 10:10:44

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

我的问题是关于在ndb中建模一对多关系。我知道这可以(至少)以两种不同的方式完成:使用重复属性或使用“外键”。我在下面创建了一个小例子。基本上我们有一篇文章可以有任意数量的标签。我们假设可以删除标记,但添加标记后无法更改。我们也假设我们不担心交易安全。

我的问题是:建模这些关系的首选方式是什么?

我的考虑因素:

  • 方法(A)要求为每个标记添加两个写入 文章(一篇用于文章,一篇用于标签)而方法 (B)只需要一次写入(只是标签)。
  • 方法(A)利用 获取文章的所有标签时,ndb的缓存机制 在接近(B)的情况下,需要查询(并且还需要一些查询) 自定义缓存)

我是否有一些我在这里缺少的东西,还有其他需要考虑的因素吗?

非常感谢你的帮助。

示例(A):

class Article(ndb.Model):
    title = ndb.StringProperty()
    # some more properties
    tags = ndb.KeyProperty(kind="Tag", repeated=True)

    def create_tag(self):
        # requires two writes
        tag = Tag(name="my_tag")
        tag.put()
        self.tags.append(tag)
        self.put()

    def get_tags(self):
        return ndb.get_multi(self.tags)

class Tag(ndb.Model):
    name = ndb.StringProperty()
    user = ndb.KeyProperty(Kind="User") #  User that created the tag
    # some more properties

示例(B):

class Article(ndb.Model):
    title = ndb.StringProperty()
    # some more properties

    def create_tag(self):
        # requires one write
        tag = Tag(name="my_tag", article=self.key)
        tag.put()

    def get_tags(self):
        # obviously we could cache this query in memcache
        return Tag.gql("WHERE article :1", self.key)

class Tag(ndb.Model):
    name = ndb.StringProperty()
    article = ndb.KeyProperty(kind="Article")
    user = ndb.KeyProperty(Kind="User") #  User that created the tag
    # some more properties

3 个答案:

答案 0 :(得分:6)

您是否看过以下有关使用Structured Properties https://developers.google.com/appengine/docs/python/ndb/properties#structured的信息。关于ContactAddresse的简短讨论可以简化您的问题。另请参阅https://developers.google.com/appengine/docs/python/ndb/queries#filtering_structured_properties。讨论很短暂。

此外,展望不允许加入的事实,选项A看起来更好。

答案 1 :(得分:1)

如前所述,数据存储区中没有连接,因此所有"外键#34;这个概念并不适用。可以做的是使用Query类来查询数据存储区中的正确标记。

例如,如果您使用的是端点,则:

class Tag(ndb.model):
    user = ndb.UserProperty()

请求期间执行:

query.filter(Tag.user == endpoints.get_current_user())

答案 2 :(得分:0)

在大多数情况下,方法(A)应该是首选。虽然添加标记需要两次写入,但这可能比读取标记的频率低得多。只要你没有大量的标签,它们都应该适合重复的Key属性。

正如您所提到的,通过键获取标记要比执行查询快得多。此外,如果您只需要标记的名称和用户,则可以创建标记,其中User作为父键,Name作为标记的ID:

User -> Name -> Tag

要创建此标记,您可以使用:

tag = Tag(id=name, parent=user, ...)
article.tags.push(tag)
ndb.put_multi([tag, article])

然后当你检索标签时,

for tag in article.tags:
    user = tag.parent()
    name = tag.id()

然后,您存储在Article.tags中的每个密钥都将包含用户密钥和Tag名称!这样可以避免您在Tag中阅读以获取这些值。