将不同的排序键响应映射到 Appsync 架构值
Map different Sort Key responses to Appsync Schema values
这是我的架构:
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!
}
type PaginatedModels {
models: [Model!]!
nextToken: String
}
我想打电话给 'getAllModels' 并获得所有数据,并填写所有标签。
但事情是这样的。标签通过排序键存储。像这样
PartionKey | SortKey
Model-0 | Model-0
Model-0 | Tag-Tree
Model-0 | Tag-Building
是否可以通过 DynamoDB 解析器将 'Tag' 排序键转换为架构中的 Tags: [String]
数组?或者我必须通过 lambda 做一些额外的事情吗?还是有更聪明的方法来做到这一点?
澄清一下,您是否在 DynamoDB 中存储这样的对象:
{ PartitionKey (HASH), Tag (SortKey), Name, Version, FBX, CreatedAt, Description }
并使用 DynamoDB 查询操作获取给定 HashKey 的所有行。
Query #PartitionKey = :PartitionKey
并返回一个对象列表,其中一些对象具有不同的 "Tag" 值,其中一个是 "Model-0" (也就是与分区键相同的值),我假设记录包含记录的所有其他值。例如
[
{ PartitionKey, Tag: 'ValueOfPartitionKey', Name, Version, FBX, CreatedAt, ... },
{ PartitionKey, Tag: 'Tag-Tree' },
{ PartitionKey: Tag: 'Tag-Building' }
]
您绝对可以轻松地编写解析器逻辑,将模型对象列表缩减为具有 "Tags" 列表的单个对象。让我们从单个项目开始,看看如何实现 getModel(id: ID!): Model
查询:
首先定义将获取分区键的所有行的响应映射模板:
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
"expression": "#PartitionKey = :id",
"expressionValues" : {
":id" : {
"S" : "${ctx.args.id}"
}
},
"expressionNames": {
"#PartitionKey": "PartitionKey" # whatever the table hash key is
}
},
# The limit will have to be sufficiently large to get all rows for a key
"limit": $util.defaultIfNull(${ctx.args.limit}, 100)
}
然后到 return 将 "Tag" 减少到 "Tags" 的单个模型对象,您可以使用此响应映射模板:
#set($tags = [])
#set($result = {})
#foreach( $item in $ctx.result.items )
#if($item.PartitionKey == $item.Tag)
#set($result = $item)
#else
$util.qr($tags.add($item.Tag))
#end
#end
$util.qr($result.put("Tags", $tags))
$util.toJson($result)
这将 return 像这样的响应:
{
"PartitionKey": "...",
"Name": "...",
"Tags": ["Tag-Tree", "Tag-Building"],
}
基本上我认为这没有问题,但它的有效性取决于您的查询模式。将其扩展到 getAll 使用是可行的,但需要进行一些更改,并且很可能是一个非常低效的 Scan 操作,因为 table 实际信息将很少,因为许多记录实际上只是标签。您可以使用 GSI 轻松缓解这种情况,但更多 GSI 意味着更多 $.
作为替代方法,您可以将标签存储在不同的 "Tags" table 中。这样,您只需将模型信息存储在模型 table 中,将标签信息存储在标签 table 中,并利用 GraphQL 为您执行连接。在这种方法中,Query.getAllModels 在模型 table 上执行 "Scan"(或查询),然后 Model.Tags 对标签 table 执行查询的解析器(HK:ModelPartitionKey,SK:标签)。然后您可以获取模型的所有标签,然后创建 GSI 以获取标签的所有模型。您确实需要考虑现在嵌套的 Model.Tag 查询将在每个模型中调用一次,但查询操作速度很快,而且我已经看到它在实践中运行良好。
希望这对您有所帮助:)
这是我的架构:
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!
}
type PaginatedModels {
models: [Model!]!
nextToken: String
}
我想打电话给 'getAllModels' 并获得所有数据,并填写所有标签。
但事情是这样的。标签通过排序键存储。像这样
PartionKey | SortKey
Model-0 | Model-0
Model-0 | Tag-Tree
Model-0 | Tag-Building
是否可以通过 DynamoDB 解析器将 'Tag' 排序键转换为架构中的 Tags: [String]
数组?或者我必须通过 lambda 做一些额外的事情吗?还是有更聪明的方法来做到这一点?
澄清一下,您是否在 DynamoDB 中存储这样的对象:
{ PartitionKey (HASH), Tag (SortKey), Name, Version, FBX, CreatedAt, Description }
并使用 DynamoDB 查询操作获取给定 HashKey 的所有行。
Query #PartitionKey = :PartitionKey
并返回一个对象列表,其中一些对象具有不同的 "Tag" 值,其中一个是 "Model-0" (也就是与分区键相同的值),我假设记录包含记录的所有其他值。例如
[
{ PartitionKey, Tag: 'ValueOfPartitionKey', Name, Version, FBX, CreatedAt, ... },
{ PartitionKey, Tag: 'Tag-Tree' },
{ PartitionKey: Tag: 'Tag-Building' }
]
您绝对可以轻松地编写解析器逻辑,将模型对象列表缩减为具有 "Tags" 列表的单个对象。让我们从单个项目开始,看看如何实现 getModel(id: ID!): Model
查询:
首先定义将获取分区键的所有行的响应映射模板:
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
"expression": "#PartitionKey = :id",
"expressionValues" : {
":id" : {
"S" : "${ctx.args.id}"
}
},
"expressionNames": {
"#PartitionKey": "PartitionKey" # whatever the table hash key is
}
},
# The limit will have to be sufficiently large to get all rows for a key
"limit": $util.defaultIfNull(${ctx.args.limit}, 100)
}
然后到 return 将 "Tag" 减少到 "Tags" 的单个模型对象,您可以使用此响应映射模板:
#set($tags = [])
#set($result = {})
#foreach( $item in $ctx.result.items )
#if($item.PartitionKey == $item.Tag)
#set($result = $item)
#else
$util.qr($tags.add($item.Tag))
#end
#end
$util.qr($result.put("Tags", $tags))
$util.toJson($result)
这将 return 像这样的响应:
{
"PartitionKey": "...",
"Name": "...",
"Tags": ["Tag-Tree", "Tag-Building"],
}
基本上我认为这没有问题,但它的有效性取决于您的查询模式。将其扩展到 getAll 使用是可行的,但需要进行一些更改,并且很可能是一个非常低效的 Scan 操作,因为 table 实际信息将很少,因为许多记录实际上只是标签。您可以使用 GSI 轻松缓解这种情况,但更多 GSI 意味着更多 $.
作为替代方法,您可以将标签存储在不同的 "Tags" table 中。这样,您只需将模型信息存储在模型 table 中,将标签信息存储在标签 table 中,并利用 GraphQL 为您执行连接。在这种方法中,Query.getAllModels 在模型 table 上执行 "Scan"(或查询),然后 Model.Tags 对标签 table 执行查询的解析器(HK:ModelPartitionKey,SK:标签)。然后您可以获取模型的所有标签,然后创建 GSI 以获取标签的所有模型。您确实需要考虑现在嵌套的 Model.Tag 查询将在每个模型中调用一次,但查询操作速度很快,而且我已经看到它在实践中运行良好。
希望这对您有所帮助:)