使用Appsync和DynamoDB通过ID获取项目的有效方法

时间:2019-04-12 03:58:13

标签: amazon-dynamodb slug aws-appsync aws-amplify

我想创建并使用slug url,以通过AWS Amplify与在Appsync和DynamoDB之上构建的博客网站一起使用。子弹是文章标题和提示的组合;例如/article/an-interesting-post-on-bats-123abc将返回标题为“蝙蝠有趣的帖子”的帖子。这将是相对简单的,但有一些限制:

  • DynamoDB的GetItem操作仅适用于主键。
  • 项目的主键无法更改。为了“更改”主键,您必须删除并重新创建一个项目。
  • Article实体数据具有一定的可延展性,因为用户可以更改文章的标题,文本等。标题的更改可能会保证对条目的更改。实际上,用户无需输入标题就可以保存Article,因此,该条不能成为主键的基础(因为创建项是必需的)。

很显然,对于主键来说,该子弹本身是一个糟糕的选择;但是,段是当前可用于创建查询的唯一输入(作为路径参数)。 鉴于这些限制,如果我只有the子,查询Article的最有效方法是什么?

在这一点上,我在设计阶段就足够早了,可以修改几个资源:(1)文章的网址,(2)DynamoDB设计(即主键和排序键是什么);和(3)Appsync模式。

当前,Article模式包含:

type Article @model {
  id: ID! // the primary key
  authorId: String
  title: String
  text: String
  slug: String
}

尽管可以扫描子弹,但这似乎是将Dynamo用作常规访问模式的一种无效方法。我曾经想过要用{来作为主键,将authorId用作排序键或局部二级索引。这似乎与Medium和StackOverflow创建帖子网址的方式类似。

1 个答案:

答案 0 :(得分:0)

您可以在slug属性上创建secondary index。然后,您将必须使用dynamoDB查询操作创建另一个GraphQL查询及其相应的解析程序。查询远比扫描有效。

为此,您有两个选择。在第一个中,您可以遵循查询操作的设计并返回文章列表,而不是单个文章。这可以使用connectionModels或简单地返回列表的类型来实现。

例如

## Schema
type ArticleConnection{
  items: [Article]
}

type Query {
    getArticle(id: ID!): Article
    getArticleBySlug(slug: String): ArticleConnection // Query on secundary index
}


## Resolver
## Request Mapping Template
{
    "version": "2017-02-28",
    "operation": "Query",
    "scanIndexForward": true,
    "index" : "slug",
    "select" : "ALL_ATTRIBUTES",
    "query" : {
        "expression" : "slug = :slug",
        "expressionValues" : {
            ":slug" : $util.dynamodb.toDynamoDBJson("${ctx.args.slug}")
        }
    }
}

## Response Mapping Template
$util.toJson($ctx.result)

或者如果您想与第一个查询保持一致,则可以执行以下操作

## Schema
type Query {
    getArticle(id: ID!): Article
    getArticleBySlug(slug: String): Article // Query on secundary index
}


## Resolver
## Request Mapping Template
{
    "version": "2017-02-28",
    "operation": "Query",
    "scanIndexForward": true,
    "index" : "slug",
    "select" : "ALL_ATTRIBUTES",
    "query" : {
        "expression" : "slug = :slug",
        "expressionValues" : {
            ":slug" : $util.dynamodb.toDynamoDBJson("${ctx.args.slug}")
        }
    }
}

## Response Mapping Template
#if($ctx.result.items.size() > 0)
   $util.toJson($ctx.result.items[0])
#else
    null
#end