我正在创建一个Google App Engine应用程序(python),并且我正在学习一般框架。我一直在查看NDB数据存储区的教程和文档,而且我在概念上遇到了一些困难。我有大量的SQL数据库背景,而且我从未使用过任何其他类型的数据存储系统,因此我认为我遇到了麻烦。
我目前的理解是:NDB数据存储区是一组具有属性(类似于DB字段/列)的实体(类似于DB记录)。使用模型(类似于DB模式)创建实体。每个实体都有一个存储时为其生成的密钥。这是我遇到麻烦的地方,因为这些密钥似乎与SQL DB概念中的任何东西都没有类比。它们看起来类似于表的主键,但它们更紧密地绑定到记录,实际上它们是字段本身。这些NDB密钥不是实体的属性,但被视为与实体分离的对象。如果实体存储在数据存储区中,则可以使用其密钥检索该实体。
我最大的问题之一是你在哪里获得钥匙?我看到的一些文档显示了简单创建密钥的示例。我不明白这一点。似乎存储实体时,put()
方法返回一个可以在以后使用的密钥。那么,如果数据存储区生成原始密钥,您如何才能创建密钥并定义id?
我似乎正在努力解决的另一件事是带有钥匙的祖先的概念。您可以定义任何类型的父键。是否有预定义的架构?例如,如果我有一个名为' Person'的模型子类,并且我创建了一个类型的密钥' Person',我可以将该密钥用作任何其他类型的父密钥吗?就像我想要一个' Shoe'成为“人”的孩子的关键。关键,我还能宣布一辆汽车'成为同一个孩子的关键人物'键?或者在添加' Shoe'之后我将无法键?
我真的只是对来自主要SQL背景的人的NDB数据存储及其API的简单解释。
答案 0 :(得分:12)
我认为你的想法过于复杂。创建实体时,您可以为其指定自己选择的命名密钥,也可以将其保留,并让数据存储区选择数字ID。无论哪种方式,当您调用put
时,数据存储区将返回密钥,该密钥以[<entity_kind>, <id_or_name>]
的形式存储(实际上这也包括应用程序ID和任何命名空间,但我会将其留下来清晰度)。
您可以通过为实体组提供祖先来实现它们的实体成员。虽然通常这样做,但祖先实际上并不需要引用现有实体。祖先发生的一切都是实体的密钥包含祖先的密钥:所以它现在看起来像[<parent_entity_kind>, <parent_id_or_name>, <entity_kind>, <id_or_name>]
。您现在只能通过包含其父键来获取实体。因此,在您的示例中,Shoe实体可以是Person的子项,无论该Person是否先前已创建:它是知道祖先的孩子,而不是相反的。
(请注意,祖先路径可以任意扩展:子实体本身可以是祖先,依此类推。在这种情况下,组由树顶部的实体确定。)
将实体保存为组的一部分在一致性方面具有优势,因为实体组内的查询始终保证完全一致,而查询外部的查询最终是一致的。但是,也存在一些缺点,即整个组中实体组的写入速率限制为每秒1次。
答案 1 :(得分:7)
数据存储区keys与内部SQL行标识符稍微类似,但当然不完全相同。 Appengine中的标识符有点像SQL主键。为了支持服务器云中的许多应用程序实例分散并发创建新密钥,AppEngine在内部生成密钥以保证唯一性。您的应用程序定义了AppEngine用于为其密钥生成器设定种子的参数(应用程序标识符,可选命名空间,种类和可选实体标识符)。如果您未提供标识符,AppEngine将generate a unique numeric identifier you can read。
最终的一致性需要时间,因此request multiple new keys in bulk偶尔会更高效。然后,AppEngine会为您生成一系列数字实体标识符。您可以read their values from keys作为KeyProperty metadata。
对于group together writes和transactions,Ancestry用于isolation所有类型的相关实体。没有预定义的架构,但每个孩子只能使用一个父级。
在您的示例中,一个特定的Shoe可能有一个特定的Person作为父级。另一个特殊的鞋可以有一匹马作为父母。另一个鞋子可能没有父母。所有类型的许多实体都可以拥有相同的父级,因此多个Car实体也可以将该初始Person作为父级。数据存储区是无模式的,因此您的应用程序可以允许或禁止Car将Horse作为父级。
请注意,子级知道其父级,但父级不知道其子级,因为实现这会影响可伸缩性。