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