我在GraphQL AppSync查询上得出了相当复杂的DynamoDB解析器链。我很想知道的是,我是否可以以较少的DynamoDB查询方式进行设计。
这是我的GraphQL模式:
type Tag {
PartitionKey: ID!
SortKey: ID!
TagName: String!
TagType: String
}
type Model {
PartitionKey: ID!
Name: String
Version: Int
FBX: String
# ms since epoch
CreatedAt: AWSTimestamp
Description: String
Tags: [String]
}
type Query {
GetAllModels(count: Int, nextToken: String): PaginatedModels!
}
这是我正在做的查询:
query GetAllModels{
GetAllModels {
Models {
PartitionKey
Name
Version
CreatedAt
Description
Tags {
TagName
TagType
}
}
}
}
我的DynamoDB表设置如下:
PartionKey | SortKey | TagName | TagType | ModelName | Description
Model-0 | Model-0 | ModelZero | Blah Blah
Model-0 | Tag-Pine |
Model-0 | Tag-Apple |
Tag-Pine | Tag-Pine | Pine | Tree
Tag-Apple | Tag-Apple | Apple | Fruit
所以在我的解析器中,我要去
GetAllModels将使用两个过滤器进行扫描。一个用于PartitionKey的过滤器以“ Model-”开头,另一个用于SortKey的过滤器以“ Model-”开头。这是所有模型。
接下来,在模型对象的“标签”上附加了一个解析程序。这将使用两个表达式进行查询。一个用于PartitionKey = source.Parition,另一个用于SortKey begin_with'Tag-',这使我获得了模型上的所有标签。
接下来,Tag对象上有两个解析器。一个在TagName上,另一个在TagType上。这些函数使用PartitionKey = source.Sort和SortKey = source.SortKey设置为键来直接获取GetItem以获取其适当的值。
因此,每个扫描的模型最终都会向DynamoDB发出另外3个查询。对我来说,这似乎有点过分。但是我看不到任何其他方式可以做到这一点。有什么方法可以在一个查询中同时获取TagName和TagType?
有没有更好的方法来解决这个问题?
答案 0 :(得分:1)
我看到了一些我个人会改变的东西。首先,我将避免嵌套DynamoDB扫描操作。至少其中之一可以用更快的查询操作代替。第二个是,我将考虑重新考虑如何存储数据。当前,没有列出模型对象的好方法。
为什么没有列出模型对象的好方法?
假定每个模型对象将具有多个标签,那么您将拥有一个表,其中该表很少由模型对象填充。也就是说,在100行中,您可能有20-50个模型,具体取决于平均模型有多少个标签。在DynamoDB中,将根据分区键对表进行拆分,从而使共享同一分区键的行彼此靠近存储,以加快查询操作。使用分区键本质上是单个模型对象的唯一ID的设置,这意味着我们可以轻松地获得单个模型对象。由于这些记录也在附近,因此您也可以快速获取单个对象的标签。
问题。
DynamoDB扫描操作一次查看每个分区,读取 limit 请求所允许的尽可能多的记录,如果 limit 足够大,则读取所有记录,然后,仅在从各个分区读取记录之后,才应用过滤器表达式,然后返回最终结果。这意味着您可能会要求使用前10个模型,但是由于限制是在扫描过滤器之前应用的,因此您很可能只会获得1个模型(如果一个模型有9个或更多标签,而DynamoDB在读取该模型时将耗尽该限制。第一个分区)。当来自许多不同的数据库系统时,这可能看起来很奇怪,这是其设计的重要考虑因素。
以下是解决此问题的两种解决方案:
1。将模型存储在一个表中,将标签存储在另一个表中。
像DynamoDB这样的NoSQL数据库允许您在同一张表中存储许多类型的数据,但是将它们拆分出来没有任何问题。传统上,在没有联接操作或类似操作的NoSQL数据库中使用多个表可能会很痛苦,但是幸运的是,对于我们来说,我们可以使用GraphQL为我们“联接”数据。通过这种方法, Model 表具有一个名为“ id”的分区键,并且您的 GetAllModels 解析器仍在扫描,但这一次是在模型表上。这样,表格就不会稀疏,并且当您要求10个模型时,您将获得10个模型。 Tag 表的分区键应为 modelId ,排序键应为 tagId 。然后,您将在 Model.tags 字段上具有一个解析器,该解析器针对 Tag 表进行查询,并查找具有 modelId == $ ctx.source的行.id 。
从本质上讲,这是在作为cli cli的一部分推出的新graphql转换工具中@model和@connection的工作方式。您可以在此处看到更多信息,尽管文档在编写时仍在改进中。 https://aws-amplify.github.io/amplify-js/media/api_guide
2。将模型和标签存储在同一表中,但更改密钥结构。
如果您可以肯定地说每种数据类型(例如,型号和标签)的数据量少于10GB,则此方法有效。对于这种方法,您只有一个表,其PartitionKey为 Type ,排序键为 id 。创建对象时,可以使用 Type (例如“标签”或“模型”等)和唯一的 id (例如uuid)来创建对象。要列出相同类型的对象,您可以对要列出的类型的分区键执行DynamoDB查询操作,例如“标签”或“模型”。然后,您可以使用GSI来有效地查找相关对象。在您的情况下,您将为每个 Tag 对象存储一个“ modelId”。然后,您将使用“ modelId”作为分区密钥来创建GSI。要列出给定模型的所有标签,然后可以对该GSI进行DynamoDB查询操作。
我敢肯定,还有更多的方法可以做到这一点,但希望这有助于指出正确的方向。