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

问题描述 投票:0回答:1

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

  • DynamoDB的GetItem操作仅适用于主键。
  • 无法更改项目的主键。要“更改”主键,您必须删除并重新创建项目。
  • Article实体数据随着时间的推移具有可塑性,因为用户可以更改文章的标题,文本等。对标题的更改可能需要更改slug。实际上,用户可以在没有输入标题的情况下保存Article,因此slug不能作为主键的基础(因为它是创建项目所必需的)。

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

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

目前,Article架构包含:

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

尽管可以扫描slug,但这似乎是将Dynamo用于常规访问模式的低效方式。我有一个想法是将authorId作为主键,将slug作为排序键或本地二级索引。这似乎与Medium和StackOverflow创建帖子网址的方式类似。

amazon-dynamodb slug aws-appsync aws-amplify
1个回答
0
投票

您可以在slug属性上创建secondary index。然后你必须使用dynamoDB查询操作创建另一个GraphQL查询及其各自的解析器。查询比扫描更有效。

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

例如

## 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
© www.soinside.com 2019 - 2024. All rights reserved.