It is easy. You can do it in two different ways or you can use both ways to have better flexibility. ( if you already resolved it I hope it will help someone else ).
Doing it this way you can set sortDirection dynamically using query arguments.
Detailed code is given below. Before that please note this point.
First point is re your Comment type - you are using
type Comment {
id: ID!
postId: String!
}
This is not the best way to set up your Comment type linked to a Post.
Better way is:
type Comment {
postID: ID! ## select this as Primary key in DataSource in AppSync console
commentID: String! ## select this as Sort key in DataSource in AppSync console
## rest of your type definition
}
If you do this your DynamoDB table will have structure similar to one shown below ( from this AWS webpage).
( In your case UserId would be PostId and GameTitle would be CommentID )

This way, because all comments would be recorded next to each other (under same PostId ) AppSync response time would be much faster.
In AppSync docs page they also used this example:

- As @Lisa M Shon mentioned you can initiate a GSI on CommentTable where PostId is partition key and addedTime is sort key . Call it 'postID-addedTime-index' if you want to use Resolvers provided below. MAKE SURE that you select 'Number' on addedTime in GSI.

Then in your schema you can define following types:
type Comment {
postID: ID!
commentID: String!
content: String!
addedTime: Int!
}
type CommentConnection {
items: [Comment]
nextToken: String
}
type Post {
id: ID!
postContent: String!
addedTime: Int!
comments(
filter: TableCommentFilterInput,
sortDirection: SortDirection,
startFromTime: Int,
limit: Int,
nextToken: String
): CommentConnection
}
type Query {
postCommentsByAddTime(
postID: String!,
startFromTime: Int!,
sortDirection: SortDirection,
filter: TableCommentFilterInput,
count: Int,
nextToken: String
): PaginatedComments
}
You can use both - Option 1 and Option 2 and use both.
Full schema code is here ( expand the snippet below ):
type Comment {
postID: ID!
commentID: String!
content: String!
addedTime: Int!
}
type CommentConnection {
items: [Comment]
nextToken: String
}
input CreateCommentInput {
postID: ID!
commentID: String!
content: String!
addedTime: Int!
}
input CreatePostInput {
postContent: String!
addedTime: Int!
}
input DeleteCommentInput {
postID: ID!
commentID: String!
}
input DeletePostInput {
id: ID!
}
type Mutation {
createComment(input: CreateCommentInput!): Comment
updateComment(input: UpdateCommentInput!): Comment
deleteComment(input: DeleteCommentInput!): Comment
createPost(input: CreatePostInput!): Post
updatePost(input: UpdatePostInput!): Post
deletePost(input: DeletePostInput!): Post
}
type PaginatedComments {
items: [Comment!]!
nextToken: String
}
type Post {
id: ID!
postContent: String!
addedTime: Int!
comments(
filter: TableCommentFilterInput,
sortDirection: SortDirection,
startFromTime: Int,
limit: Int,
nextToken: String
): CommentConnection
}
type PostConnection {
items: [Post]
nextToken: String
}
type Query {
getComment(postID: ID!, commentID: String!): Comment
listComments(filter: TableCommentFilterInput, limit: Int, nextToken: String): CommentConnection
getPost(id: ID!): Post
listPosts(filter: TablePostFilterInput, limit: Int, nextToken: String): PostConnection
postCommentsByAddTime(
postID: String!,
startFromTime: Int!,
sortDirection: SortDirection,
filter: TableCommentFilterInput,
count: Int,
nextToken: String
): PaginatedComments
}
enum SortDirection {
ASC
DESC
}
type Subscription {
onCreateComment(
postID: ID,
commentID: String,
content: String,
addedTime: Int
): Comment
@aws_subscribe(mutations: ["createComment"])
onUpdateComment(
postID: ID,
commentID: String,
content: String,
addedTime: Int
): Comment
@aws_subscribe(mutations: ["updateComment"])
onDeleteComment(
postID: ID,
commentID: String,
content: String,
addedTime: Int
): Comment
@aws_subscribe(mutations: ["deleteComment"])
onCreatePost(id: ID, postContent: String, addedTime: Int): Post
@aws_subscribe(mutations: ["createPost"])
onUpdatePost(id: ID, postContent: String, addedTime: Int): Post
@aws_subscribe(mutations: ["updatePost"])
onDeletePost(id: ID, postContent: String, addedTime: Int): Post
@aws_subscribe(mutations: ["deletePost"])
}
input TableBooleanFilterInput {
ne: Boolean
eq: Boolean
}
input TableCommentFilterInput {
postID: TableIDFilterInput
commentID: TableStringFilterInput
content: TableStringFilterInput
addedTime: TableIntFilterInput
}
input TableFloatFilterInput {
ne: Float
eq: Float
le: Float
lt: Float
ge: Float
gt: Float
contains: Float
notContains: Float
between: [Float]
}
input TableIDFilterInput {
ne: ID
eq: ID
le: ID
lt: ID
ge: ID
gt: ID
contains: ID
notContains: ID
between: [ID]
beginsWith: ID
}
input TableIntFilterInput {
ne: Int
eq: Int
le: Int
lt: Int
ge: Int
gt: Int
contains: Int
notContains: Int
between: [Int]
}
input TablePostFilterInput {
id: TableIDFilterInput
postContent: TableStringFilterInput
addedTime: TableIntFilterInput
}
input TableStringFilterInput {
ne: String
eq: String
le: String
lt: String
ge: String
gt: String
contains: String
notContains: String
between: [String]
beginsWith: String
}
input UpdateCommentInput {
postID: ID!
commentID: String!
content: String
addedTime: Int
}
input UpdatePostInput {
id: ID!
postContent: String
addedTime: Int
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
- (related to Option 1). On Schema page of AppSync console in right hand side panel find Post and opposite to 'comments(...): CommentConnection' click 'Attach', add 'CommentTable' as source and add following Resolver code in VTL:
In request mapping template:
{
"version" : "2017-02-28",
"operation" : "Query",
"index" : "postID-addedTime-index",
"query" : {
"expression": "postID = :postID and addedTime > :startFrom",
"expressionValues" : {
":postID" : { "S" : "$context.source.id" },
":startFrom" : { "N" : "$startFromTime" }
}
},
"scanIndexForward":
true
false
true
,"limit": ${context.arguments.count}
,"nextToken": "${context.arguments.nextToken}"
}
In response mapping template:
{
"items": $utils.toJson($context.result.items)
,"nextToken": "${context.result.nextToken}"
}
- (related to Option 2). On Schema page of AppSync console in right hand side panel find Query and opposite to 'postCommentsByAddTime(...): PaginatedComments' click 'Attach', add CommentTable as data source and add following Resolver code in VTL:
In request mapping template:
{
"version" : "2017-02-28",
"operation" : "Query",
"index" : "postID-addedTime-index",
"query" : {
"expression": "postID = :postID and addedTime > :startFrom",
"expressionValues" : {
":postID" : { "S" : "${context.arguments.postID}" },
":startFrom" : { "N" : "${context.arguments.startFromTime}" }
}
}
,"limit": ${context.arguments.count}
,"nextToken": "${context.arguments.nextToken}"
}
In response mapping template:
{
"items": $utils.toJson($context.result.items)
,"nextToken": "${context.result.nextToken}"
}
That is it.
Now you can use all of following queries:
query ListPosts {
listPosts{
items {
id
postContent
comments(startFromTime: 121111112222, count: 4
) {
items {
postID
commentID
content
addedTime
}
}
}
}
}
query GetPost {
getPost(id: "6548e596-d1ed-4203-a32f-52cfab8c9b20") {
id
comments (
) {
items {
postID
commentID
content
addedTime
}
}
}
}
query GetCommentsByTime {
postCommentsByAddTime(postID: "6548e596-d1ed-4203-a32f-52cfab8c9b20", startFromTime: 12423455352342, count: 2) {
items {
postID
commentID
content
addedTime
}
}
}
postId
and a sort key onlastChangTime
. An example of such a relationship is on the AppSync console. You can look at theStart from a sample project: Event App
- Lisa M Shon