Amplify-cli: Add sort options to graphql schema

Created on 17 Jul 2019  路  14Comments  路  Source: aws-amplify/amplify-cli

Issue originally opened by @Crisp3333 as https://github.com/awslabs/aws-mobile-appsync-sdk-android/issues/200


https://github.com/awslabs/aws-mobile-appsync-sdk-android/issues/200#issue-461847003

Is your feature request related to a problem? Please describe.
For cases where a query result is returned they are automatically sorted in ascending order. There should be a clear and concise way of getting a sort in descending order.I moved from direct DynamoDB querying to implementing my app in AppSync only to find out an atomic operation is hard to figure out how to implement. I have looked at other problems associated to this and only get pointed to "set scanIndexForward" without any proper way of implementing it. Where should I add this "scanIndexForward"? knowing that graphql/AppSync has encapsulated DynamoDB operations with its own functions and implementations, and without proper knowledge of writing resolvers, it leaves one playing vtl roulette with one extra headache of learning a new language. These things cut into production time when you could be focusing on actual code.

I am aslo aware of the ModelSortDirection enum type, which I believe does some form of sorting. However, my schema is basic at minimum, that is, I am not creating @connections, @functions etc. Also this enum type is not among my generated Java files.

Describe the solution you'd like
Looking at the queries (vtl files (req)) generated by amplify push, the scanIndexForward field is left out, which of course will sort your query results in ascending order by default.
Currently this is what the generated resolvers for model queries look like (a portion of the req.vtl file of course):
#set( $ListRequest = { "version": "2017-02-28", "limit": $limit, } )

There should be away to set the scanIndexForward permanently in descending order or ascending at schema creation\modification time. I say permanently because I am assuming there must be some complications and burden for the AppSync team to let clients query DynamoDB table at will in ascending or descending order at application run time. But preferable I would like to see the sortDirection parameter become custom just like parameters nextToken, limit and filter. If the sortDirection parameter cannot be added, please at least let it be available at schema creation time to set it permanently.

A few months ago the AppSync team created the @key directive(The best thing since slide bread), which was wonderful for creating secondary index keys and sort keys.
A solution that I have been thinking about is to include sortDirection in the @key directive when creating/modifying schema. For Order model, one could define:

type Order @model @key(fields: ["customerEmail", "createdAt"], sortDirection: "DSC")

Here the sortDirection parameter would be used against the sortKey field: createdAt. For people that are not using the @key directive, there could be a way sortDirection could be targeted at the primary key (Hash key).

Describe alternatives you've considered
(1) It was pointed out that I could just log into the aws appsync console and include the "scanIndexForward" to be false, as it is true by default. However I plan to do that at last resort in case I break something. Evidently It seems that is what I have to do.

(2) Currently I am doing a reverse after query results returned (very inefficient) luckily I am working with a minimum amount of results.

(3) Spend a couple of weeks(time that I do not have) and learn velocity templating language and write my own resolver.


https://github.com/awslabs/aws-mobile-appsync-sdk-android/issues/200#issuecomment-506906907

Currently I just log into the aws appsync console choose schema and look for the resolver under query and just add "scanIndexForward": false. Doing this I just have to remember to go back and update it again after each amplify push.

feature-request graphql-transformer pending-review

Most helpful comment

With @searchable this is how I handled the sorting:

const result = await API.graphql(
  graphqlOperation(searchTickets, {
    nextToken,
    limit,
    filter,
    sort: {
      field: createdAt,
      direction: desc
    }
  })
);

This will sort the result based on createdAt field, desc. What I haven't figured out is how to sort it by relationship, say, Tickets is associated with Status:

type Ticket @model @searchable {
  id: ID!
  description: String
  title: String
  statusId: String
  status: Status @connection(keyField: "statusId")
  createdAt: AWSDateTime
  updatedAT: AWSDateTime
}

type Status @model @searchable {
  id: ID!
  name: String
  description: String
  createdAt: AWSDateTime
  updatedAT: AWSDateTime
}

And this is only 1-1 relationship, we should also consider 1-n and n-n relationships.

All 14 comments

@palpatim
Thanks for your input, will put it into our backlog.

Hi folks, any updates on how to sort fields for a list schema?

I am also interested in a simple solution for adding a default sortField to a @model -- especially one that uses the automatically-generated createdAt field.

Currently, I could add @key(fields: ["type", "createdAt"]) to enable the sortDirection input when querying, but that would require me to include createdAt in every mutation.

Also, please consider people using @searchable.

I think I am about to write my own resolver within the next month or so as this requires me to log into the account on each amplify push and add scanIndexForward each time.

With @searchable this is how I handled the sorting:

const result = await API.graphql(
  graphqlOperation(searchTickets, {
    nextToken,
    limit,
    filter,
    sort: {
      field: createdAt,
      direction: desc
    }
  })
);

This will sort the result based on createdAt field, desc. What I haven't figured out is how to sort it by relationship, say, Tickets is associated with Status:

type Ticket @model @searchable {
  id: ID!
  description: String
  title: String
  statusId: String
  status: Status @connection(keyField: "statusId")
  createdAt: AWSDateTime
  updatedAT: AWSDateTime
}

type Status @model @searchable {
  id: ID!
  name: String
  description: String
  createdAt: AWSDateTime
  updatedAT: AWSDateTime
}

And this is only 1-1 relationship, we should also consider 1-n and n-n relationships.

@aprilmintacpineda can the @searchable directive be used with the @model? I do not want to break my database, as appsync with graphql is very delicate.

@Crisp3333 Yes it can. AFAIK, you can only query types with @model.

Guys I did not even realize, sortDirection is now added. It is available when you are making queries.

@Crisp3333 oh wow really!? do you have link to documentation?

Yes, we do support sortDirection. We have this listed in our example #17 in this section - https://aws-amplify.github.io/docs/cli-toolchain/graphql#data-access-patterns

Let me know if this doesn't work for you.

I have been looking for your example #17 in this section - https://aws-amplify.github.io/docs/cli-toolchain/graphql#data-access-patterns as a graphQL query, as I have the @key and implementing sortDirection is just not working for me. I can't see how it is done. I have set up the graphql and checked the dyanmodb table and everything looks fine, then I turn to the app code and I cannot make it work, so I remade the database and changed the field to int instead of AWSDate type to see if that made a difference.

The problem for me is listing data in index order. I start with this and get a random order: const todoData = await API.graphql(graphqlOperation(listTodos) except I want it in an order, so I try this: const todoData = await API.graphql(graphqlOperation(listTodos,{sortDirection:'DESC'})) iget an error: "When providing argument 'sortDirection' you must also provide argument 'id'.", the same as before. How do I order my data - this is a pretty basic requirement non?

I have the same issue, myself. I don't want to filter the results, just sort them.

I would expect to be able to do this :
API.graphql(graphqlOperation(listTodosByName, {sortDirection:'DESC'} )).

That would be great. Am I missing something ?

@aprilmintacpineda adding searchable will much increase the cost because you will put elastic search machine upon.
the easiest solution is adding a custom LSI. which the sortKey is the sort you want to make:

An example for that will be :

type PropertyComps @model(timestamps: null) 
 @key(fields: ["targetId", "compId"]) 
 @key(name: "byTargetSortedComps", fields: ["targetId", "compScore"], queryField: "byTargetSortedComps") {
  targetId: ID!
  compId: ID!
  compScore: Float
}

the byTargetSortedComps <- the sort key is the compScore. which makes it useable with the sortDirection was added to appSync.

```{
"data": {
"getPropertyInfo": {
"comps": {
"items": [
{
"compScore": 3,
"compId": "789",
"targeId": "123"
},
{
"compScore": 2,
"compId": "456",
"targetId": "123"
},
{
"compScore": 1,
"compId": "1234",
"targetId": "123"
}
]
}
}
}
}

Was this page helpful?
0 / 5 - 0 ratings