AppEngine数据存储:分层查询



如果您正在处理一个记录层次结构,其中大多数键都有祖先,那么您是否必须在检索叶子之前创建所有键的链?

示例(Go语言):

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

如何获得thirdGenKey所描述的记录,而无需声明其上面层次结构的所有级别的键?

为了获得单个实体,它的键必须是全局唯一的——这是通过每个实体键在其实体组中是唯一的来实现的。由于这个原因,祖先路径构成了实体键的固有部分。

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

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

  • 在您的应用程序中可能不是唯一的
  • 您将服从最终的一致性。

补充tx802的回答:

如果你想按键加载一个实体,你需要它的键。如果密钥是这样一个具有父密钥的密钥,那么为了形成/创建该密钥,还需要先创建父密钥。父键是键的部分,就像数字ID或字符串名称一样。

从实现的角度看:数据存储。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)

最新更新