将不同的排序键响应映射到 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 查询将在每个模型中调用一次,但查询操作速度很快,而且我已经看到它在实践中运行良好。

希望这对您有所帮助:)