Reputation: 1006
Provided a very simple model in graphql.schema
, how would I perform a simple sort query?
type Todo @model
id: ID!
text: String!
}
Which generates the following in queries.js
.
export const listTodos = /* GraphQL */ `
query ListTodos(
$filter: ModelTodoFilterInput
$limit: Int
$nextToken: String
) {
listTodos(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
text
}
nextToken
}
}
`;
I have found multiple sources pointing me in the direction of the @key
directive. This similar question addresses that approach (GraphQL with AWS Amplify - how to enable sorting on query).
While that may seem promising and successfully generates new queries I can use, all the approaches I have tried require that I filter the data before sorting it. All I want to do is sort my todo results on a given column name, with a given sort direction (ASC/DESC).
This is how I would perform a simple (unsorted) query:
const todos = await API.graphql(graphqlOperation(listTodos));
I would be looking to do something along the lines of:
const todos = await API.graphql(graphqlOperation(listTodos, {sortField: "text", sortDirection: "ASC"} ))
.
Upvotes: 5
Views: 4433
Reputation: 66
Declaring @searchable
incurs pointless extra server cost if all you need is straight forward sorting. It spins up an EBS and an OpenSearch that will be about $20 a month minumum.
Instead you need to use the @index
directive.
As per the documentation here: https://docs.amplify.aws/guides/api-graphql/query-with-sorting/q/platform/js/
In your model, add the @index
directive to one of the fields with a few parameters:
type Todo @model {
id: ID!
title: String!
type: String! @index(name: "todosByDate", queryField: "todosByDate", sortKeyFields: ["createdAt"])
createdAt: String!
}
By declaring the queryField
and the sortKeyField
you will now have a new query available to once you push your amplify config:
query todosByDate {
todosByDate(
type: "Todo"
sortDirection: ASC
) {
items {
id
title
createdAt
}
}
}
The field you declare this directive on can not be empty (notice the ! after the field name)
This is a much better way of doing it as opposed to @searchable
, which is massively overkill.
Upvotes: 4
Reputation: 1006
I've accepted MTran's answer because it feels to me it is the nearest thing to an actual solution, but I've also decided to actually opt for a workaround. This way, I avoid adding a dependency to ElasticSearch.
I ended up adding a field to my schema and every single entry has the same value for that field. That way, I can filter by that value and still have the entire table of values, that I can then sort against.
Upvotes: 1
Reputation: 1809
Decorate your model with the @searchable
directive, like so:
type Todo @model @searchable
{
id: ID!
text: String!
}
After that, you can query your data with sorting capabilities like below:
import { searchToDos } from '../graphql/queries';
import { API, graphqlOperation } from 'aws-amplify';
const toDoData = await API.graphql(graphqlOperation(searchToDos, {
sort: {
direction: 'asc',
field: 'text'
}
}));
console.log(toDoData.data.searchToDos.items);
For more information, see
Upvotes: 7