首页 > 解决方案 > 将不同的排序键响应映射到 Appsync 架构值

问题描述

所以这是我的架构:

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

Tags: [String]是否可以通过 DynamoDB 解析器将“标签”排序键转换为架构中的数组?或者我必须通过 lambda 做一些额外的事情吗?还是有更聪明的方法来做到这一点?

标签: amazon-web-servicesamazon-dynamodbgraphqlaws-appsync

解决方案


澄清一下,您是否在 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' }
]

您绝对可以轻松编写解析器逻辑,将模型对象列表减少为具有“标签”列表的单个对象。让我们从单个项目开始,看看如何实现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)
}

然后,要返回将“标签”简化为“标签”的单个模型对象,您可以使用此响应映射模板:

#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)

这将返回如下响应:

{
  "PartitionKey": "...",
  "Name": "...",
  "Tags": ["Tag-Tree", "Tag-Building"],
}

从根本上说,我认为这没有问题,但它的有效性取决于您的查询模式。将此扩展到 getAll 使用是可行的,但需要进行一些更改,并且很可能是一个非常低效的扫描操作,因为该表将很少包含实际信息,因为许多记录实际上只是标签。您可以使用 GSI 轻松缓解这种情况,但更多 GSI 意味着更多美元。

作为替代方法,您可以将标签存储在不同的“标签”表中。这样,您只需将模型信息存储在 Model 表中,将标签信息存储在 Tag 表中,并利用 GraphQL 为您执行连接。在这种方法中,Query.getAllModels对 Model 表执行“扫描”(或 Query),然后有一个Model.Tags解析器对 Tag 表(HK:ModelPartitionKey,SK:Tag)执行查询。然后,您可以获取一个模型的所有标签,然后创建一个 GSI 来获取一个标签的所有模型。您确实需要考虑,现在每个模型都会调用一次嵌套的Model.Tag查询,但是查询操作很快,而且我已经看到这在实践中运行良好。

希望这可以帮助 :)


推荐阅读