How to sort on a field in list query in aws-amplify?
Asked Answered
T

2

7

How to sort on a field in amplify graphql api? I am trying to sort on a field while getting a list of an model.

Eg: Sorting on createdDate in listOrder query.

Any help please?

Tabu answered 7/6, 2019 at 4:59 Comment(0)
F
10

@key directive might be what you want.

Suppose you are listing Orders of a specific customer by createdAt timestamp, and suppose this is your schema:

type Order @model @key(fields: ["customerEmail", "createdAt"]) {
    customerEmail: String!
    createdAt: String!
    orderId: ID!
}

This will create a primary index with a hash key of customerEmail and a sort key of createdAt that is managed on your behalf by AppSync resolvers. This will allow you to run this query:

query ListOrdersForJack {
  listOrders(customerEmail:"[email protected]") {
    items {
      orderId
      customerEmail
      createdAt
    }
  }
}

Why no explicit sort keyword? The sorting will happen automatically because the @key specifies that the field createdAt should be used as the sort key. You can refer https://github.com/aws-amplify/amplify-cli/issues/1502 for a similar discussion.

Freud answered 7/6, 2019 at 15:49 Comment(2)
Perfect! That's exactly what I am looking for. But while pushing the code, I am getting below error Schema Errors: Unknown directive "key". GraphQL request (5:1) 4: ) 5: @key(fields: ["id", "createdAt"]) Tabu
This link help me resolve compile error [github.com/aws-amplify/amplify-cli/issues/1566]Tabu
L
1

2021 update: I tried the solution provided by Yik (where something in Amplify auto-fills createdDate provided as a sortKey automatically), but it seems that sorting in AWS Amplify is not working as you would expect.

To save others' time I wrote this longer post with the following model that deals with 1 user that has Many notifications.

I used "aws-amplify": "^4.3.1" and "aws-amplify-react-native": "^5.0.3".

Filtering from 'owner' object

I used the schema below (intended to be one-to-many relationship):

type User
  @model {
  id: ID!
  username: String
  lastname: String
  firstname: String
  description: String
  avatar: String
  externalHandles: [ExternalHandle]
  followerCount: Int
  followingCount: Int
  verifiedEmail: String
  createdDate: AWSTimestamp
  enableMessageRequests: Boolean
  --> notifications: [UserNotification] @connection(keyName: "byUser", fields: ["id"])
}


type UserNotification 
  @model 
  @key(name: "byUser", fields: ["userID", "createdAt"])
  @auth(rules: [{allow: public}, {allow: public}]) {
  id: ID!
  text: String
  ---> userID: ID!
  ---> author: User! @connection(fields: ["userID"])
  clubID: ID  
  club: Club @connection(fields: ["clubID"])
  type: NotificationsType
  seen: Boolean
  time: AWSTimestamp
  createdAt: String!
}

Then I run 'amplify mock api' to generate queries and see them in the GraphiQ web console (+ I added some dummy data).

Now, if you want to list notifications from the user ('owner' object), you can specify the sort direction.

enter image description here

Filtering directly

But if you try to list notifications for the given user directly (e.g. by using userID as a filter and not by using parent object), the sort direction is missing.

enter image description here

Also as you can see on right, the results are NOT SORTED AUTOMATICALLY :

enter image description here

To solve it, I needed to update the schema, where I added queryField: "userNotificationsByDate" which will create a new, separate query. See the updated model below:

type UserNotification 
 @model @key(name: "byUser", fields: ["userID", "createdAt"], queryField: "userNotificationsByDate") 
 @key(name: "byNotifications", fields: ["userID", "createdAt"]) 

Now you will get the sorted results - but you still must specify userID / or primary key value that you had defined in @key directive. @Key directive/annotation uses the format of ["primaryKey", "sortKey"]. If you will leave the primaryKey value empty, the query will fail. See the results below when using this new generated query:

enter image description here

Filtering directly - Repeating primary key on all objects

Finally, if you e.g. want to list notifications (without knowing to which user they belong), you would need to define @key with a primary key value that is the same in all persisted objects. See example model:

type UserNotification 
  @model 
  @key(name: "justByDate", fields: ["dummyType", "createdAt"])
  @auth(rules: [{allow: public}, {allow: public}]) {
  id: ID!
  createdAt: String!
  dummyType: String!
  ...

and then you would need to create notifications like this (using the same primary key):

mutation {
  createUserNotification(input: {
   userID: "d69f62fe21b299",
   dummyType: "ShouldBeSameForAllRooms"}) {
    id
  }
}

Note: Besides String, you can also use 'enum' in the schema for this dummy primary key.

If you would use enum, such as

enum NotificationsType {
  START_MEETING
  JOINED_ROOM
}

type UserNotification @model 
@key(name: "byUser", fields: ["userID", "createdAt"], queryField: "userNotificationsForSpecifiedUserByDate")
@key(name: "byUser3", fields: ["type", "createdAt"], queryField: "userNotificationsByDate") 
  @auth(rules: [{allow: public}, {allow: public}]) {
  id: ID!
  userID: ID!
  text: String
  clubID: ID
  author: User! @connection(fields: ["userID"])
-> type: NotificationsType!
  seen: Boolean
  time: AWSTimestamp
  createdAt: String!
}

you can get notifications that belong to e.g. some group (START_MEETING or JOINED_ROOM in my example) SORTED with the following query:

query MyQuery {
  userNotificationsByTypeSortedBtDate(sortDirection: ASC, type: START_MEETING) {
    items{
      createdAt
    }
  }
}

See the results:

enter image description here

Lovett answered 22/10, 2021 at 15:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.