代码之家  ›  专栏  ›  技术社区  ›  jcgh582

如何使用google云数据存储nodejs读取事务中的所有实体

  •  0
  • jcgh582  · 技术社区  · 7 年前

    当我尝试运行一个查询来读取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: {} },
    

    所以我需要使用祖先查询。如何创建祖先查询?这似乎取决于您在数据存储中构建层次结构的方式。所以我的下一个问题是,假设我在数据存储中创建的每个实体都是这样保存的(标识符对于保存的entityData是唯一的)

    const entityKey = datastore.key({ namespace: ns, path: [kind, identifier] });
    { key: entityKey, method: 'upsert', data: entityData };
    

    如何读取事务中的db?我想如果我知道标识符,我可以这样做,但是标识符是从我保存在种类中的entityData构建的,我需要读取种类的实体来找出我在db中的内容(鸡蛋问题)。我希望我错过了什么。

    更多上下文

    我的问题涉及赞助人员。我储存了一种 people 在数据存储中,每个实体都是 person 由唯一标识符、名称和等级组成。我有另一种叫做 relationships 其中每个实体都是 relationship 包含两个民族标识符 sponsor & sponsee (链接到一起的人)。因此,我将其结构化为RDB。如果我想获得个人赞助人,我会从db获得所有关系,循环他们返回关系 斯波西 然后在db中查询 赞助商 其中 关系 .

    考虑到我必须为人及其链接/关系建模,我如何用实体组/祖先的“数据存储”方式构建它。

    让我们假设RDB是不可能的。

    示例场景

    两个人必须从应用程序/数据库中删除(假设他们在同一天离开了公司)。当我删除某人时,我也想删除他们的关系。我删除的两个人共享一段关系(一个是赞助另一个)。假设第一笔交易成功,即我删除了一个人及其关系。下一次交易,我删除一个人,然后在关系中搜索相关关系,我发现一个已经被删除,因为最终一致。我试着找到那种关系的人,但他们并不存在。爆炸了。

    注意:每个事务包装删除个人(&他们的关系。多人等于多笔交易。

    我的应用程序不关心可扩展性

    1 回复  |  直到 7 年前
        1
  •  2
  •   Dan Cornilescu    7 年前

    您的理解是正确的:

    • 您不能使用祖先查询,因为您的实体不在祖先关系中(即不在同一实体组中)。

    • 不能在事务内执行非祖先查询。请注意,您在单个事务中读取的实体数也不能超过25个(每个实体位于单独的实体组中)。从…起 Restrictions on queries :

    事务内的查询必须是祖先查询

    云数据存储 transactions 对属于up的实体进行操作 至25 entity groups ,但事务内部的查询必须 祖先查询。在事务中执行的所有查询必须 specify an ancestor . 有关更多信息,请参阅 Datastore Transactions .

    在与您类似的上下文中,典型的方法是在事务之外执行查询,通常只是 keys only 查询-获取实体键,然后通过在事务内进行键查找来读取相应的实体(一次最多25个)。并仅在绝对需要时使用事务,例如,请参阅以下相关讨论: Ancestor relation in datastore .

    您的问题显然表明您正在以关系数据库的心态来处理数据存储。如果你的应用程序基本上需要关系数据(你没有描述你要做什么),数据存储 可以 不是最好的产品。看见 Choosing a storage option . 我并不是说你不能将数据存储与关系数据一起使用,在许多情况下仍然可以这样做,但需要更仔细的设计-这些限制正在推动基于可伸缩数据存储的应用程序(IMHO可能比使用关系数据库实现的可伸缩性要高得多)

    构建数据RDB样式(对于数据存储来说可以)和在RDB样式中使用数据RDB样式(不太好)之间存在差异。

    在您提到的特定使用场景中,您不需要查询 sponsor relationship :您已经拥有 赞助商 的键 关系 实体,您所需要做的就是通过键查找它,这可以在事务中完成。

    获取全部 关系 a的实体 person 需要一个查询,由 成为 赞助商 或者 sponsee . 但这真的必须在交易中完成吗?或者如果你错过了结果列表a,这是可以接受的吗 关系 几秒钟前创建的?或者有一个最近被删除了?如果稍后再重复查询,它最终会(dis)出现在列表中(请参见 Eventual Consistency on Reading an Index ). 如果这是可以接受的(依我看,关系不会经常更改,在更改后立即进行查询的可能性很小),那么您不需要在事务中进行查询,因此您不需要在 people 关系 实体。非常适合扩展性。

    另一个考虑因素:循环浏览 关系 实体:也不一定必须在事务中完成。而且,如果关系的数量很大,循环可能会到达请求截止日期。一种更具可扩展性的方法是使用查询游标并将工作拆分为多个任务/请求,每个任务/请求处理列表的一个子集。请参见此类方法的Python示例: How to delete all the entries from google datastore?

    对于每个 删除案例:

    • 添加类似于 being_deleted (在交易中)的财产 标记删除并防止在删除过程中使用,例如在执行删除任务时创建新关系。在应用程序逻辑中(也在事务中)需要的任何位置添加此标志的检查。
    • 获取所有列表 关系 并使用上述循环技术将其删除
    • 在最后一个循环迭代中,当没有关系剩下时,将另一个任务排入队列(大量延迟),以重新检查在前一个循环执行中可能由于最终一致性而错过的任何最近的关系。如果有显示,请重新运行循环,否则只需删除

    如果不考虑可伸缩性,还可以重新设计数据结构,以便在所有实体之间使用祖先(将它们放在同一个实体组中),然后可以做您想要的事情。例如,参见, What would be the purpose of putting all datastore entities in a single group? . 但有许多潜在风险需要注意,例如: