Is your feature request related to a problem? Please describe.
I'm unsure whether this is already possible in AWS Amplify, but here is my problem. I'm building a simple contact list app.
type Contact @model @auth(rules: [{ allow: owner }]) {
id: ID!
firstName: String
lastName: String
city: String
email: String
telephone: String
}
Until now, I was using Amplify's helper methods for the query.
API.graphql(graphqlOperation(listContacts, { limit: 1000 }));
Afterwards I would sort the contacts on the client side by lastName
and then by firstName
. Now the first user has over a thousand contacts so he doesn't get all his contacts. People have told me to use pagination, which is good, but the problem I have is, let's say I over 11 pages and each page has 100 contacts. Then I could only sort each page by first and last Name, but not all contacts.
Describe the solution you'd like
A good solution would be, if you could sort the contacts in the query by some fields. E.g.
API.graphql(graphqlOperation(listContacts, { limit: 100, nextToken, sortBy: { firstName: 'gte', lastName: 'gte' }));
This way the query would be sorted and fetch the correct contacts and the nextToken
would be useful.
Describe alternatives you've considered
The only alternative I have considered is fetching all contacts prior to loading the list, but this approach will cause longer and longer loading times as the amount of entities grow.
And alternative API design would be to let user describe the sorting in the schema
type Contact @model @auth(rules: [{ allow: owner }]) {
id: ID!
firstName: String @sort(2, "gte")
lastName: String @sort(1, "gte")
city: String
email: String
telephone: String
}
Where the number determines the order of sorts and the string the way to sort. But this would be way less flexible than using the dynamic approach described above.
This is part of my generated graphql/queries.js
:
export const listUsers = `query ListUsers(
$filter: ModelUserFilterInput
$limit: Int
$nextToken: String
) {
listUsers(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
It would be great if listUsers
had an argument sortBy
@janhesters We are actively working on the @key directive that will help solve this use case for you. The code (https://github.com/aws-amplify/amplify-cli/pull/1463) and docs (https://github.com/aws-amplify/docs/pull/689/files) are currently in PR.
The general idea is that you will be able to define a schema like this:
type Contact
@model
@key(name: "ByOwnerLastNameFirstName", fields: ["owner", "lastName", "firstName"], queryField: "contactsByOwner")
@auth(rules: [{ allow: owner }])
{
id: ID!
firstName: String
lastName: String
city: String
email: String
telephone: String
owner: String
}
This will create a GSI named "ByOwnerLastNameFirstName" with a hash key of owner and a composite sort key of lastName#firstName that is managed on your behalf by AppSync resolvers. This will allow you to run a query:
query {
contactByOwner(owner: "myuser") {
items {
id
owner
firstName
lastName
}
}
}
The sorting will happen automatically because the @key specifies that the lastName/firstName combinations of fields should be used as the sort key.
@mikeparisstuff Awesome, thanks for letting me know! I have three questions:
API.graphql(graphqlOperation(listContacts, { limit: 100, nextToken, sortBy: { firstName: 'gte', lastName: 'gte' }));
) ?max_length
one?Why not use a local secondary index聽instead of a global secondary index?
@dancomanlive What do you mean by that?
Was referring to "This will create a GSI named "ByOwnerLastNameFirstName" with a hash key of owner and a composite sort key of lastName#firstName that is managed on your behalf by AppSync resolvers."
A primary key can be a partition key or a combination of a partition(hash) key and sort(range) key. A local secondary index has the same partition key and different sort keys. A global secondary index can be a partition key(different from the partition key of the primary key and all other GSIs) or a combination of a partition key and sort key.
We need to return "all the items", which means a scan. It is not possible to order the results of a scan so the solution is to use a GSI. Ok I get it now.
We launched support for custom indexes today. You can find docs for the same out here - https://aws-amplify.github.io/docs/cli/graphql#key
Please let us know if you're still not able to solve your problem through this solution and we'll re-open this issue for you.
Thanks for the update! If I understand correctly, if I wanted to be able to query a whole table by each field, I would do:
type Foo @model
@key(name: "Field1", fields: ["[any field]", "field1"], queryField: "fooSortedByField1")
@key(name: "Field2", fields: ["[any field]", "field2"], queryField: "fooSortedByField2")
@key(name: "Field3", fields: ["[any field]", "field3"], queryField: "fooSortedByField3")
{
id: ID!
field1: Int
field2: Int
field3: Int
}
and query eg:
query FooByField1 {
fooSortedByField1() {
items {
id
field1
field2
field3
}
nextToken
}
}
I'm not sure how to say that I want it sorted ascending vs descending.
Yeah where do we add the sortDirection?
Wanted to echo the comments by @lorensr and @nino-moreton : Any word on how to add sortDirection?
Also, when we set up a GSI as @mikeparisstuff describes, is there any way to remove the "owner" arg in the query? It is redundant because we're using auth, so we're only getting contacts by that user anyway. For the example contact list api, I would like to run a query "contactByOwner" without any args, and have automatically return all contacts that are owned by the user, sorted by name.
I thought maybe changing the global sort key would do it by:
@key(fields: ["id", "lastName", "firstName"])
But when I run a listContacts, even though I just get the contacts owned by the user, the result is not sorted by name.
Hi guys, did the question about sortDirection ever get answered or do I really have to make custom resolver just for that?
@voidarg there's an open feature request for this at #1629
Like @khusmann mentioned, it would be great to be able to omit the first field entirely, and just sort the entire list of values.
Most helpful comment
Yeah where do we add the sortDirection?