如何使用 google 云数据存储 nodejs 读取事务中的所有实体
How do I read all entities of a kind in a transaction with google cloud datastore nodejs
当我尝试 运行 查询以读取具有 google 数据存储的事务中的所有实体时,它给我这个错误
{ Error: Only ancestor queries are allowed inside transactions.
at /root/src/node_modules/grpc/src/client.js:554:15
code: 3,
metadata: Metadata { _internal_repr: {} },
所以我需要使用祖先查询。如何创建祖先查询?它似乎取决于您如何构建数据存储中的层次结构。所以我的下一个问题是,假设我在数据存储区中创建的每个实体都像这样保存(标识符对于保存的实体数据是唯一的)
const entityKey = datastore.key({ namespace: ns, path: [kind, identifier] });
{ key: entityKey, method: 'upsert', data: entityData };
如何在事务中读取数据库?我想如果我知道标识符我就可以做到,但是标识符是从我保存在种类中的实体数据构造的,我需要读取种类的实体来弄清楚我在数据库中有什么(鸡蛋问题) .我希望我遗漏了一些东西。
更多上下文
我的问题涉及赞助人。我在数据存储中存储了一种 people
,其中每个实体都是一个 person
,由唯一标识符、名称和等级组成。我有另一种称为 relationships
的类型,其中每个实体都是一个 relationship
,包含两个人的标识符,sponsor
和 sponsee
(将人们链接在一起)。所以我将其结构化为 RDB。如果我想获得赞助商,我会从数据库中获取所有关系,遍历它们返回 person
是 sponsee
的关系,然后在数据库中查询 sponsor
relationship
.
鉴于我必须对人物及其 links/relationships.
进行建模,我如何使用实体 groups/ancestors 以 'datastore' 的方式构建它
让我们假设 RDB 是不可能的。
示例场景
必须从 app/db 中删除两个人(假设他们在同一天离开公司)。当我删除某人时,我也想删除他们的关系。我删除的两个人共享关系(一个正在赞助另一个)。假设第一笔交易成功,即我删除了一个人和他们的关系。下一个事务,我删除一个人,然后搜索相关关系的关系,我发现一个已经被删除的关系,因为最终一致。我试着找到那个关系的人,但他们不存在。爆炸了。
注意:每笔交易都包含删除人员及其关系。多人等于多次交易。
我的应用程序不关心可伸缩性
您的理解是正确的:
您不能使用祖先查询,因为您的实体不存在祖先关系(即不在同一实体组中)。
您不能在事务内执行非祖先查询。请注意,您也不能在单个事务中读取超过 25 个实体(每个实体都在一个单独的实体组中)。来自 Restrictions on queries:
Queries inside transactions must be ancestor queries
Cloud Datastore transactions operate on entities belonging to up
to 25 entity groups, but queries inside transactions must be
ancestor queries. All queries performed within a transaction must
specify an ancestor. For more information, refer to Datastore
Transactions.
在与您类似的上下文中,典型的方法是在事务之外执行查询,通常只是 keys only
queries - to obtain the entity keys, then read the corresponding entities (up to 25 at a time) by key lookup inside transactions. And use transactions only when it's absolutely needed, see, for example, this related discussion: Ancestor relation in datastore。
您的问题显然表明您正在以关系数据库的思维方式处理数据存储。如果您的应用程序从根本上需要关系数据(您没有描述您想要做什么),数据存储区 可能 不是它的最佳产品。参见 Choosing a storage option。我并不是说您不能将数据存储与关系数据一起使用,它在许多情况下仍然可以完成,但需要更仔细的设计 - 这些限制正在推动基于可扩展数据存储的应用程序(恕我直言可能更具可扩展性您可以使用关系数据库实现)
构建数据 RDB 样式(对数据存储没问题)和在 RDB 样式中使用它(不太好)是有区别的。
在您提到的特定使用场景中,您不需要查询 relationship
的 sponsor
:您已经在 relationship
中拥有 sponsor
的密钥=] 实体,你需要做的就是按键查找,这可以在交易中完成。
获取 person
的所有 relationship
实体需要一个查询,由 person
过滤,即 sponsor
或 sponsee
。但它真的必须在交易中完成吗?或者,如果您可能在结果列表中错过了几秒钟前创建的 relationship
,这是否可以接受?或者有一个最近被删除的?如果稍后重复查询,它最终会(消失)出现在列表中(参见 Eventual Consistency on Reading an Index)。如果这是可以接受的(恕我直言,关系不会经常改变,在改变后立即查询的机会很小)那么你不需要在事务中进行查询因此你不需要祖先关系在 people
和 relationship
实体之间。非常适合可扩展性。
另一个考虑因素:遍历 relationship
个实体的列表:也不一定必须在事务中完成。而且,如果关系数量很大,循环可能会到达请求截止日期。一种更具可扩展性的方法是使用查询游标并将工作拆分到多个 tasks/requests,每个游标处理列表的一个子集。请参阅此类方法的 Python 示例:How to delete all the entries from google datastore?
对于每个 person
删除案例:
- 向
person
添加类似 being_deleted
属性(在事务中)的内容以标记删除并防止在删除期间使用任何内容,例如在删除任务时创建新关系正在进步。在应用程序逻辑中的任何需要的地方(也在事务中)添加对此标志的检查。
- 获取那个人的所有
relationship
键的列表并使用上面提到的循环技术删除它们
- 在最后一次循环迭代中,当没有剩余关系时,将另一个任务排队,慷慨地延迟,以重新检查由于最终一致性而可能在先前循环执行中遗漏的任何最近关系。如果出现任何重新 运行 循环,否则只需删除
person
如果可伸缩性不是问题,您还可以重新设计数据结构以在所有实体之间使用祖先(将它们放在同一实体组中),然后您就可以做您想做的事了。例如,参见 。但是有很多潜在的风险需要注意,例如:
- 整个实体组的最大速率为 1 write/sec(每个实体组最多 500 个实体),参见
- 大型交易耗时过长且达到请求截止日期,请参阅 Dealing with DeadlineExceededErrors
- 较高的争用风险,请参阅
当我尝试 运行 查询以读取具有 google 数据存储的事务中的所有实体时,它给我这个错误
{ Error: Only ancestor queries are allowed inside transactions.
at /root/src/node_modules/grpc/src/client.js:554:15
code: 3,
metadata: Metadata { _internal_repr: {} },
所以我需要使用祖先查询。如何创建祖先查询?它似乎取决于您如何构建数据存储中的层次结构。所以我的下一个问题是,假设我在数据存储区中创建的每个实体都像这样保存(标识符对于保存的实体数据是唯一的)
const entityKey = datastore.key({ namespace: ns, path: [kind, identifier] });
{ key: entityKey, method: 'upsert', data: entityData };
如何在事务中读取数据库?我想如果我知道标识符我就可以做到,但是标识符是从我保存在种类中的实体数据构造的,我需要读取种类的实体来弄清楚我在数据库中有什么(鸡蛋问题) .我希望我遗漏了一些东西。
更多上下文
我的问题涉及赞助人。我在数据存储中存储了一种 people
,其中每个实体都是一个 person
,由唯一标识符、名称和等级组成。我有另一种称为 relationships
的类型,其中每个实体都是一个 relationship
,包含两个人的标识符,sponsor
和 sponsee
(将人们链接在一起)。所以我将其结构化为 RDB。如果我想获得赞助商,我会从数据库中获取所有关系,遍历它们返回 person
是 sponsee
的关系,然后在数据库中查询 sponsor
relationship
.
鉴于我必须对人物及其 links/relationships.
进行建模,我如何使用实体 groups/ancestors 以 'datastore' 的方式构建它让我们假设 RDB 是不可能的。
示例场景
必须从 app/db 中删除两个人(假设他们在同一天离开公司)。当我删除某人时,我也想删除他们的关系。我删除的两个人共享关系(一个正在赞助另一个)。假设第一笔交易成功,即我删除了一个人和他们的关系。下一个事务,我删除一个人,然后搜索相关关系的关系,我发现一个已经被删除的关系,因为最终一致。我试着找到那个关系的人,但他们不存在。爆炸了。
注意:每笔交易都包含删除人员及其关系。多人等于多次交易。
我的应用程序不关心可伸缩性
您的理解是正确的:
您不能使用祖先查询,因为您的实体不存在祖先关系(即不在同一实体组中)。
您不能在事务内执行非祖先查询。请注意,您也不能在单个事务中读取超过 25 个实体(每个实体都在一个单独的实体组中)。来自 Restrictions on queries:
Queries inside transactions must be ancestor queries
Cloud Datastore transactions operate on entities belonging to up to 25 entity groups, but queries inside transactions must be ancestor queries. All queries performed within a transaction must specify an ancestor. For more information, refer to Datastore Transactions.
在与您类似的上下文中,典型的方法是在事务之外执行查询,通常只是 keys only
queries - to obtain the entity keys, then read the corresponding entities (up to 25 at a time) by key lookup inside transactions. And use transactions only when it's absolutely needed, see, for example, this related discussion: Ancestor relation in datastore。
您的问题显然表明您正在以关系数据库的思维方式处理数据存储。如果您的应用程序从根本上需要关系数据(您没有描述您想要做什么),数据存储区 可能 不是它的最佳产品。参见 Choosing a storage option。我并不是说您不能将数据存储与关系数据一起使用,它在许多情况下仍然可以完成,但需要更仔细的设计 - 这些限制正在推动基于可扩展数据存储的应用程序(恕我直言可能更具可扩展性您可以使用关系数据库实现)
构建数据 RDB 样式(对数据存储没问题)和在 RDB 样式中使用它(不太好)是有区别的。
在您提到的特定使用场景中,您不需要查询 relationship
的 sponsor
:您已经在 relationship
中拥有 sponsor
的密钥=] 实体,你需要做的就是按键查找,这可以在交易中完成。
获取 person
的所有 relationship
实体需要一个查询,由 person
过滤,即 sponsor
或 sponsee
。但它真的必须在交易中完成吗?或者,如果您可能在结果列表中错过了几秒钟前创建的 relationship
,这是否可以接受?或者有一个最近被删除的?如果稍后重复查询,它最终会(消失)出现在列表中(参见 Eventual Consistency on Reading an Index)。如果这是可以接受的(恕我直言,关系不会经常改变,在改变后立即查询的机会很小)那么你不需要在事务中进行查询因此你不需要祖先关系在 people
和 relationship
实体之间。非常适合可扩展性。
另一个考虑因素:遍历 relationship
个实体的列表:也不一定必须在事务中完成。而且,如果关系数量很大,循环可能会到达请求截止日期。一种更具可扩展性的方法是使用查询游标并将工作拆分到多个 tasks/requests,每个游标处理列表的一个子集。请参阅此类方法的 Python 示例:How to delete all the entries from google datastore?
对于每个 person
删除案例:
- 向
person
添加类似being_deleted
属性(在事务中)的内容以标记删除并防止在删除期间使用任何内容,例如在删除任务时创建新关系正在进步。在应用程序逻辑中的任何需要的地方(也在事务中)添加对此标志的检查。 - 获取那个人的所有
relationship
键的列表并使用上面提到的循环技术删除它们 - 在最后一次循环迭代中,当没有剩余关系时,将另一个任务排队,慷慨地延迟,以重新检查由于最终一致性而可能在先前循环执行中遗漏的任何最近关系。如果出现任何重新 运行 循环,否则只需删除
person
如果可伸缩性不是问题,您还可以重新设计数据结构以在所有实体之间使用祖先(将它们放在同一实体组中),然后您就可以做您想做的事了。例如,参见
- 整个实体组的最大速率为 1 write/sec(每个实体组最多 500 个实体),参见
- 大型交易耗时过长且达到请求截止日期,请参阅 Dealing with DeadlineExceededErrors
- 较高的争用风险,请参阅