Google app engine ndb建模

Google app engine ndb建模,google-app-engine,app-engine-ndb,Google App Engine,App Engine Ndb,我是ndb的新手。我的结构大体上是这样的: a = [b, c] b = [d, e, f] d = [g, h] e = [k, l, m, n] f = [o] c = [p, r, t] 我有下面的型号 class Child(ndb.Model): name = ndb.StringProperty() child = ndb.KeyProperty(kind="Child", repeated=True) class Root(ndb.Model): nam

我是ndb的新手。我的结构大体上是这样的:

a = [b, c]
b = [d, e, f]
d = [g, h]
e = [k, l, m, n]
f = [o]
c = [p, r, t]
我有下面的型号

class Child(ndb.Model):
    name = ndb.StringProperty()
    child = ndb.KeyProperty(kind="Child", repeated=True)

class Root(ndb.Model):
    name = ndb.StringProperty()
    child = db.StructuredProperty(Child, repeated=True)
我不能这样做,因为ndb不允许我重复,因为我已经重复了


对该结构建模的正确方法是什么?

如果您只想在单个“根”上存储多个“子”实体,则可以使用
LocalStructuredProperty
来包含
模型(但这意味着它不会被索引)。在讨论嵌套的结构化属性时,中有一个关于此行为的提示:

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

对嵌套关系建模的另一个选项是在键上使用祖先。例如,假设您的根密钥路径是:
('Root',1)
。您可以使用键
('Root',1',Child',1)
('Root',1',Child',5)
,等等在其下方添加子项,每次都将“Child”附加到键路径。然后,我们希望查询对象的子对象,您可以使用祖先查询,例如:

def create_child(parent, name):
    new_child = Child(parent=parent.key, name=name)
    new_child.put()
    return new_child

def get_children(parent):
    return Child.query(ancestor=parent.key)

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

class Root(ndb.Model):
     name = ndb.StringProperty()
在这一点上,您甚至不再需要
根目录
,因为您可以分配任意键路径,也可以使用
名称
作为ID,并存储较少的信息


这就是说,它实际上完全取决于您实际尝试建模的内容,这里没有足够的信息来理解您的意思。

如果您只想在一个“根”上存储多个“子”实体,您可以使用
LocalStructuredProperty
来包含
模型(但这意味着它不会被索引)。在讨论嵌套结构化属性时,中有一个关于此行为的提示:

尽管StructuredProperty可以重复,StructuredProperty可以包含另一个StructuredProperty,但请注意:如果一个结构化属性包含另一个,则只能重复其中一个。解决方法是使用LocalStructuredProperty,它不具有此约束(但不允许查询其属性值)

类似这样的嵌套关系建模的另一个选项是在键上使用祖先。例如,假设您的根键路径是:
('Root',1)
。您可以使用键
('Root',1',Child',1)
('Root',1',Child',5)在其下方添加子项
,依此类推,每次都将“Child”附加到密钥路径。然后,如果您想查询对象的子对象,可以使用祖先查询,例如:

def create_child(parent, name):
    new_child = Child(parent=parent.key, name=name)
    new_child.put()
    return new_child

def get_children(parent):
    return Child.query(ancestor=parent.key)

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

class Root(ndb.Model):
     name = ndb.StringProperty()
此时您甚至不需要有
Root
了,因为您可以分配任意的键槽,也可以使用
name
作为ID,并存储较少的信息


也就是说,它实际上完全取决于您实际尝试建模的内容,这里没有足够的信息来理解您的意思。

我不明白您为什么需要在孩子身上使用
KeyProperty
。您可以这样建模您的关系:

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

class Root(ndb.Model):
    name = ndb.StringProperty()
    child = ndb.KeyProperty(repeated=True)

c1 = Child(name="b").put()
c2 = Child(name="c").put()
a = Root(child=[c1,c2]).put() # put returns the key; otherwise you would need c1.key() here
children_keys = a.get().child # [Key(Child, 1234), Key(Child, 4567)]
# to retrieve the children, you could do
children = [ key.get() for key in children_keys ]

我不明白为什么您需要在孩子身上使用
KeyProperty
。您可以这样对您的关系进行建模:

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

class Root(ndb.Model):
    name = ndb.StringProperty()
    child = ndb.KeyProperty(repeated=True)

c1 = Child(name="b").put()
c2 = Child(name="c").put()
a = Root(child=[c1,c2]).put() # put returns the key; otherwise you would need c1.key() here
children_keys = a.get().child # [Key(Child, 1234), Key(Child, 4567)]
# to retrieve the children, you could do
children = [ key.get() for key in children_keys ]

请记住几件事。假设您将记录想象成文件系统中的文件

  • KeyProperty是指向另一个文件的指针
  • 重复属性仅存储多个值
  • 在本例中根本没有理由使用结构化属性,所以让我们跳过它
因此,如果通过重复属性使“根”对象“包含”所有子对象,则会导致根文件每秒只能更新一次,并且最终会变得太大

因此,作为替代,您有一些选择。您可以使用祖先查询,如Jeff所提到的。或者,您可以使用所有指针并使用查询对任何节点的子节点进行子查询:

class Node(ndb.Model):
    parent = ndb.KeyProperty(kind='Node')

    def get_children(self):
        return Node.query().filter(Node.parent == self.key)
您可以使用get_children来获取任何节点的子节点。请注意,这部分最终是一致的,因此最近添加的节点通常不会在get_children中显示一秒钟左右

root = Node(parent=None)
child1 = Node(parent=root)
child2 = Node(parent=root)
child3 = Node(parent=root)
sub_child1 = Node(parent=child1)

请记住几件事。假设您将记录想象成文件系统中的文件

  • KeyProperty是指向另一个文件的指针
  • 重复属性仅存储多个值
  • 在本例中根本没有理由使用结构化属性,所以让我们跳过它
因此,如果通过重复属性使“根”对象“包含”所有子对象,则会导致根文件每秒只能更新一次,并且最终会变得太大

因此,您可以使用一些选择,例如Jeff所提到的使用祖先查询。或者,您可以使用所有指针并使用查询来子节点的子节点:

class Node(ndb.Model):
    parent = ndb.KeyProperty(kind='Node')

    def get_children(self):
        return Node.query().filter(Node.parent == self.key)
您可以使用get_children来获取任何节点的子节点。请注意,这部分最终是一致的,因此最近添加的节点通常不会在get_children中显示一秒钟左右

root = Node(parent=None)
child1 = Node(parent=root)
child2 = Node(parent=root)
child3 = Node(parent=root)
sub_child1 = Node(parent=child1)

由于根类型和子类型的实体几乎相同,我看到您尝试建模的数据是同类实体之间一对多关系的经典示例。此类关系的建模如下:

class RelatedKind(ndb.Model):
    name = ndb.StringProperty()
    root = ndb.KeyProperty(kind="RelatedKind")
要创建实体,请执行以下操作:

a = RelatedKind(name='a')
a_key = a.put()

b = RelatedKind(name='b', root=a_key)
b_key = b.put()

c = RelatedKind(name='c', root=a_key)
c_key = c.put()

# To get all 'child' of a;

child_a = RelatedKind.query(root == a_key).fetch()

print(child_a) 
# >>> [b_key, c_key]

使用数据存储查询和keyproperty,您可以实现相同的建模,而无需重复使用。

由于根类型和子类型的实体几乎相同,我看到您尝试建模的数据是同类实体之间一对多关系的经典示例。modellin