【问题标题】:Repeated nested properties of StructuredPropertyStructuredProperty 的重复嵌套属性
【发布时间】:2016-01-14 13:22:26
【问题描述】:

虽然 NDB 文档说:

虽然 StructuredProperty 可以重复,并且 StructuredProperty 可以包含另一个 StructuredProperty,但请注意:如果一个结构化属性包含另一个,则只能重复其中一个

在我看来,对文档最清晰的解释可以正确地写为“如果一个结构化属性包含另一个结构化属性”。

在这种情况下,我希望这样的事情可以工作:

class KeyList(ndb.Model):
  keys = ndb.KeyProperty(repeated=True)

class Collection(ndb.Model):
  lists = ndb.StructuredProperty(KeyList, repeated=True)

但是,这会失败并出现错误:

TypeError:此 StructuredProperty 不能使用重复=True,因为它的模型类 (KeyList) 包含重复的属性(直接或间接)。

似乎不能在重复的 StructuredProperty 中嵌套 任何 个重复的属性。

从代码来看,这个looks to be the intended behaviour

在这种情况下,开发应用服务器可能与记录的行为不同。如果我阅读的文档是正确的,那么the condition in the development server giving rise to the above error 的修复可能类似于:

if modelclass._has_repeated and isinstance(modelclass, StructuredProperty):
   # ...

AppEngine StructuredProperty 是否应该能够包含重复的属性(重复的 StructuredProperty 除外)?

问题报告在这里:https://github.com/GoogleCloudPlatform/appengine-python-vm-runtime/issues/40

编辑值得注意的是,golang docs 是这样说的:

结构切片是有效的,包含切片的结构也是如此。但是,如果一个结构包含另一个结构,则最多可以重复其中一个。这取消了递归定义的结构类型:任何(直接或间接)包含 []T 的结构 T。

我从中得到的暗示是,重复结构上的重复非结构属性在 BigTable 级别并不是天生禁止的,而是 Python 实现的副作用。

如果没有进一步的证实,我不会依赖这个暗示。

【问题讨论】:

  • 我遇到了同样的问题,虽然文档说有可能但不是。
  • 使用 LocalStructuredProperty 代替。您可以嵌套多个级别。但是请注意,此属性将存储为 blob。
  • @janscas 作为 blob,无法对 LocalStructuredProperty 的属性进行索引。
  • 我知道...但这是将模型嵌套在同一实体中的唯一方法
  • 文档看起来很清楚。如果您想要索引结构化属性,请不要嵌套它们。

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


【解决方案1】:

这是我们文档中的一个错误 --

使用StructuredPropertys,你只能有一层重复的属性。


一些背景:

ndb 在写入数据存储之前通过分解属性来处理StructuredPropertys。比如:

class Inner(ndb.Model):
  a = ndb.StringProperty()

class Outer(ndb.Model):
  inner = ndb.StructuredProperty(Inner, repeated=True)

如果我们写:Outer(inner=[Inner(a="1"), Inner(a="2")]),这实际上会被写入数据存储区:

{
  inner.a = ["1", "2"]
}

但是,如果 Inner.a 被重复,我们可以这样写:

 Outer(inner=[Inner(a=["1", "3"]), Inner(a=["2", "4"])])

这将被写入 Datastore,如下所示:

{
  inner.a : ["1", "3", "2", "4"]
}

然后当我们读到这个时,我们不知道如何解析,因为所有这些都是有效的:

Outer(inner=[Inner(a=["1", "3"]), Inner(a=["2", "4"])])
Outer(inner=[Inner(a=["1", "3", "2"]), Inner(a=["4"])])
Outer(inner=[Inner(a=["1"]), Inner(a=["3"]), Inner(a=["2"]), Inner(a=["4"])])
Outer(inner=[Inner(a=[]), Inner(a=["1", "3", "2", "4"])])

请注意,其他库(例如 Objectify)可以通过存储用于索引的爆炸属性和可以维护反序列化结构的整个数据集的未索引 blob 来避免此问题。

【讨论】:

    【解决方案2】:

    结构化属性的文档明确指出:

    虽然 StructuredProperty 可以重复,并且 StructuredProperty 可以包含另一个 StructuredProperty,但请注意:如果一个结构属性包含另一个,则只能重复其中一个。一种解决方法是使用 LocalStructuredProperty,它没有此约束(但不允许对其属性值进行查询)。

    【讨论】:

      猜你喜欢
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-02
      相关资源
      最近更新 更多