Search code examples
graphqlamazon-dynamodbaws-amplify

GraphQL DynamoDb filter List field


I'm trying to use a graphQL API using AWS Amplify to list books that i've stored in DynamoDB filtered on a field that is a List type.

Schema

  id: ID!
  title: String
  authorId: String
  genre: [String]
  ...
}

I'm doing this:

API.graphql(graphqlOperation(listBooks, {
            filter: {
                genre: {
                    contains: category,
                }
            },
        }))

But the only books being returned are the books with a single element and that element matches the category, for example when the category is "History" this will match

[{S: "History"}]

but this will not match

[ { "S" : "History" }, { "S" : "Politics and Social Sciences" }]

My ModelBookFilterInput is this:

input ModelBookFilterInput {
  id: ModelIDInput
  genre: ModelStringInput
  ...
}

And the ModelStringInput has the contains: String attribute on it so it looks like it supports this.

I'm not sure what i'm doing wrong, any input appreciated.


Solution

  • It turns out I was neglecting to use the nextToken in the payload. the query will only look at 10 elements at a time by default so it's the dev's responsiblity to continue querying until they have enough matching results

    Example of method to use nextToken:

    /**
     * @desc Recursively fetch all items in a list query using nextToken
     * @param {Object} query The query object from cda-graphql in use.
     * @param {Object} variables The variables to pass to query.
     * @returns {Array} Array of all items received from queries.
     */
    import { API, graphqlOperation } from 'aws-amplify';
    
    async function fetchItemsNextToken({ query, variables, limit}) {
        const results = [];
        while (results.length < limit) {
            const { data } = await API.graphql(graphqlOperation(query, variables));
            const key = Object.keys(data).find(k => k.includes('list'));
            const res = data[key]; // res = { items: [], nextToken: '' }
    
            results.push(...res.items);
            if (!res.nextToken) break;
    
            // eslint-disable-next-line no-param-reassign
            variables.nextToken = res.nextToken;
        }
        return new Promise((resolve, reject) => {
            resolve(results);
        });
    }
    
    export default fetchItemsNextToken;