将用户数据作为实体组存储在 Google Cloud Datastore 中

Storing user data in Google Cloud Datastore as an Entity Group

我正在尝试找到将用户存储在 google 数据存储区(使用 nodejs)中的最佳方式。我有 userId 和 userData object:

userId: "some-random-string"

userData: {
    info: {
        name: "name",
        email: "test@email.com"
    },
    profile: {
        username: "user",
        status: "using"
    },
    stats: {
        stuffDone: 12,
        stuffNotDone: 20
    },
    inventory: {
        money: 100,
        items: ["first", "second", "third"]
    }
}

我知道我可以将所有这些存储为一个实体,但如果我要单独更新所有嵌套的 object(信息、配置文件、统计数据、库存)。

所以我将拥有根实体(可能不存在):

datastore.key(["Users", userId])

然后我会创建 4 children 来存储用户数据:

datastore.key(["Users", userId, "UserData", "Info"); --> userData.info
datastore.key(["Users", userId, "UserData", "Profile"); --> userData.profile
datastore.key(["Users", userId, "UserData", "Stats"); --> userData.stats
datastore.key(["Users", userId, "UserData", "Inventory"); --> userData.inventory

只有用户会更新数据,因此争用应该不是问题。创建用户后,我一次不需要更新多个 child。

所以说统计数据每分钟更新一次,我可以直接用密钥更新它:

datastore.key(["Users", userId, "UserData", "Stats");

最好的做法是将其拆分而不是将整个用户 object 重写为单个实体并且必须重写所有索引吗?


使用实体组我仍然可以一次查询所有用户数据:

query = datastore.createQuery().hasAncestor(datastore.key(["Users", userId]));

然后我只需要处理它以将其返回到上面的 userData object 中。我只需要在用户登录时执行一次,所有其他时间我需要获取用户数据,它只会是一个 child,我可以通过按键获取 child。


如果我不应该使用这样的实体组,那么我可以通过将用户的每个部分存储在单独的实体中来做同样的事情,例如:

datastore.key(["UsersInfo", userId); --> userData.info
datastore.key(["UsersProfile", userId); --> userData.profile
datastore.key(["UsersStats", userId); --> userData.stats
datastore.key(["UsersInventory", userId); --> userData.inventory

然后我仍然可以单独更新它们,但我认为获取所有数据会更加费力,因为我需要执行 4 个查询而不是祖先查询。


如果我每分钟只更新一次 userData.stats 和 userData.profile,这些实体组或多个实体是否是必需的,或者我应该只使用一个实体。统计数据和配置文件 objects 将变得比仅几个属性更大。

根据 属性 更新模式将实体拆分为多个相关实体可能是个好主意,尤其是对于大型实体 - 避免在实体的一部分发生变化时不必要地重写整个实体(随着实体本身及其所有相关索引的更新持续时间的相关增加。参见相关

将所有实体 "pieces" 放入同一个实体组 - 如您所见,这允许您进行祖先查询以检索用户数据,只要您遵守最大 1 write/second 每个实体组。只需仔细检查您是否可以安全地假设查询结果按特定顺序出现,否则您可能需要采取措施确保每个结果都到达正确的对象。

使用单独的、非祖先相关的实体 "pieces" 允许比与祖先拆分更高的整体写入速率:每个实体最多 1 write/second。从技术上讲,您不需要执行 4 queries 来检索实体,而是需要执行 4 个键 lookup 操作,请参阅 Retrieving an entity

但是拆分实体也会增加您的数据存储成本:单个实体的单个 read/write 操作将乘以实体被拆分的 "pieces" 的数量 - 在您的情况下4 如果你 read/write 他们都在一起。

所以你必须在你的应用程序的上下文中平衡这些利弊。