Matteo Carpi
Matteo Carpi

Reputation: 592

Amplify AppSync: custom sorting and filtering with pagination

I'm trying to write a schema so that I can query models filtered by multiple keys, sorted by a custom key and paginated.

an example of my model:

type Article {
  id: ID!
  category: String!
  area: String!
  publishOn: AWSDate!
}

And an example of the query I would like to do is: retrieve all the Articles which are part of both a given category AND area, returned in descending order by publishOn in chunks of 10 items each (to implement pagination server-side, and have a lightweight UI). The response should include also the nextToken attribute that can be used to load the "next" page of the filtered articles list.

I have multiple problems with what I can do with the automatically generated schema and can't find a way to implement manually a solution that works for all what I want to do. I try and make a list of what goes wrong:

  1. Filtering

Let's say I want to query 10 articles that belong to the category "Holiday":

listArticles(filter: {category: {eq: "Holiday} }, limit: 10)

I won't get the first 10 articles that match that category, but instead, it seems that AppSync selects the first 10 items in the table, and then it filters these 10 items by the filter criteria. In other words, it seems that the sequence in which filtering and sorting are applied is the opposite of what expected. Expected: firstly filter the table by the filter critaria, then return the first 10 items of the filtered result sets.

  1. Sorting

I couldn't find a way to add sorting with AppSync, so I added searchable:

type Article (
  @searchable
) {
  id: ID!
  category: String!
  area: String!
  publishOn: AWSDate!
}

Now if I sort by date, that key will be used as nextToken and brake the pagination. This is a known issue: https://github.com/aws-amplify/amplify-cli/issues/4434

Do you have any good tip on how to find a workaround to these bugs? I dag into the documentation and in couple of issue, but didn't come up with a solution that works well...

Thanks in advance,

Matteo

Upvotes: 1

Views: 2086

Answers (2)

vantaku ramesh
vantaku ramesh

Reputation: 39

Amplify AppSync: filtering with pagination

let allClubsList = async (sport) => {
  try {
     let clubsList;
     let clubsInfoList = [];
    let nextTokenInfo = null;
    do{ 
    let clubs = await client.query({
      query: gql(clubBySportStatus),
      variables: {
        sport: sport,
        eq: { status: "ACTIVE" },
      },
      limit: 100,
      nextToken: nextTokenInfo,
      fetchPolicy: "network-only",
    });
    clubsList = clubs.data.clubBySportStatus.items;
     clubsList.forEach((item) => clubsInfoList.push(item));
      nextTokenInfo = clubs.data.clubBySportStatus.nextToken;
    } while (Boolean(nextTokenInfo));
    if (clubsInfoList && clubsInfoList.length) {
      return {
        success: true,
        data: clubsInfoList,
      };
    }
  } catch (eX) {
    console.error(`Error in allClubsList: ${JSON.stringify(eX)}`);
    return {
      success: false,
      message: eX.message,
    };
  }
};

Upvotes: 0

Lorenz Nimmervoll
Lorenz Nimmervoll

Reputation: 61

  1. Filtering

You will need a Global Secondary Index in DynamoDB to achieve such a behaviour. You can create them with the @key annotation. I your case I would create a composite key consisting of the category for the partition key and area and publishOn as the sort key(s).

type Article 
@model
@key(fields: ["id"])
@key(name: "byCategory", fields: ["category", "publishOn"])
@key(name: "byCategoryArea", fields: ["category", "area", "publishOn"])
{
  id: ID!
  category: String!
  area: String!
  publishOn: AWSDate!
}
  1. Sorting

Sorting is done by the sortDirection property which is either DESC or ASC and can only be done on the sort key.

The @searchable directive enables elasticsearch on the table, which is a fulltext search engine and probably a bit pricy for small applications and wouldn't be required here unless you would want to query based on e.g. the article description text.

listArticles(filter: {category: {eq: "Holiday"} }, limit: 10, sortDirection: DESC)

Upvotes: 1

Related Questions