2016-09-20 118 views
1

如果您正在处理记录的层次结构,其中大多数键都具有祖先,那么在您检索叶之前是否必须创建所有键的链?AppEngine数据存储:分层查询

例(围棋):

rootKey = datastore.NewKey(ctx, "EntityType", "", id1, nil) secondGenKey = datastore.NewKey(ctx, "EntityType", "", id2, rootKey) thirdGenKey = datastore.NewKey(ctx, "EntityType", "", id3, rootKey)

你如何通过thirdGenKey描述的记录,而不必申报键的所有它上面的层次结构的级别?

回答

2

为了获得一个单独的实体,其密钥必须是全局唯一的 - 这是通过每个实体密钥在其实体组中唯一实施的。出于这个原因,祖先路径构成了实体关键的固有部分。

因此,获得具有较强一致性的单个实体的唯一方法是指定其祖先路径。这可以通过密钥或祖先查询来完成。

如果你不知道完整的祖先路径,你唯一的选择是对实体的属性查询,但谨记:

  • 这可能不是你的应用程序中是唯一的
  • 你会受到最终一致性的影响。
+0

这就是我确认。因此,如果您的层次结构由许多祖先级别组成,则需要构建一个带有ID和无祖先的密钥,另一个带有ID的密钥以及该祖先的第一个密钥,另一个带有ID的密钥以及第二个密钥这个祖先等等,直到你处于正确的级别才能访问你的主要记录,是否正确?换句话说,如果你在N级有一条记录,那么你将不得不构建一个N键链,以便以较强的一致性检索它,对吗? –

+0

@DustinOprea,这是正确的。然而,你对强一致性的评论是有误导性的,但是所有的查找(明确地通过关键字获得)都是非常一致的,它与必须存在的关键祖先没有任何关系。当您执行查询(返回0-n个实体)而不将查询绑定到单个祖先(实体组)时,最终的一致性将发挥作用。 –

+0

@DanMcGrath是的..这是祖先的存在,使它成为SC,但你需要整个链下降得足够远。谢谢,丹。 –

1

为了补充tx802的回答是:

如果您想通过键载入一个实体,你需要关键。如果密钥是具有父代的密钥,为了形成/创建密钥,还需要先创建父密钥。父键键的一部分,就像数字ID或字符串名称一样。

从实现角度来看:datastore.Key是一个结构:

type Key struct { 
    kind  string 
    stringID string 
    intID  int64 
    parent *Key 
    appID  string 
    namespace string 
} 

为了构建一个Key其中有一个家长,你必须构建父键也递归。如果您发现它太冗长以至于无法始终创建密钥层次结构,则可以为其创建辅助函数。

为了简单起见,我们假设所有的键都使用相同的实体名称,而我们只使用数字ID。它可能看起来像这样:

func createKey(ctx context.Context, entity string, ids ...int) (k *datastore.Key) { 
    for _, id := range ids { 
     k = datastore.NewKey(ctx, entity, "", id, k) 
    } 
    return 
} 

有了这个辅助函数,你的榜样减少到这一点:

k2 := createKey(ctx, "EntityType", id1, id2) 
k3 := createKey(ctx, "EntityType", id1, id3) 
+0

谢谢你的进一步澄清。看起来这个模型并没有真正适应相同实体类型的同种/递归树。例如,在我的例子中,我有一个很大的分类树(其中一行中的所有子项的祖先都是父项),但是没有实际的方法来1)将表示父项的标识符存储为记录中的项,也不是2)从另一个记录中引用这些分类器中的一个(因为这些ID只对祖先是唯一的,所以递归/嵌套祖先/父键也必须作为属性存储)。 (续...) –

+0

...当然,为了立即保持一致。当然,我可以创建一个全球唯一的密钥并将其用于查找/引用,但这只是最终一致。看起来这个模型最方便,因为当你有几个离散的祖先随手可用来建立复合关键字时(动态数量级别不可行)和/或你只有少数几个异构嵌套实体类型,例如公司 - >用户>发票。思考?我很感谢你的见解。我试图弄清楚这里的模式。 –

+0

@DustinOprea存储多种“实用”方式来存储关键信息。一种选择是拥有“Key”类型的属性,并且该属性的值可以是任何“Key”值,包括具有父项的键。另一种选择是将ID列表存储在属性中(因为您只使用ID而不使用字符串名称);你甚至可以选择像''id1,id2''那样将它们存储在单个字符串中,或​​者作为一个多值属性(slice)来存储,比如'[id1,id2]';并且只有这些ID,你可以重新构建你需要的“Key”,例如,在答案中发布'createKey()'函数。 – icza