Search code examples
amazon-web-servicesamazon-dynamodbaws-appsync

Querying DynamoDB with a list in AWS AppSync


I am trying to build an AWS AppSync query with a list using IN:

{
    "version" : "2017-02-28",
    "operation" : "Query",
    "index" : "my-index",
    "query" : {
        "expression": "id IN :ids",
        "expressionValues" : { ":ids" : $util.dynamodb.toStringSet($ctx.args.ids) }
    },
    "limit": $util.defaultIfNull(${ctx.args.first}, 20),
    "nextToken": $util.toJson($util.defaultIfNullOrBlank($ctx.args.after, null))
}

However, trying it out with parameters like:

query ListItemsWithIdList {
  listItemsWithIdList(first:20, ids: ["id1", "id2"]) {
    items {
      id
    }
    nextToken
  }
}

It throws an error:

Unable to parse the JSON document: 'Unexpected character ('S' (code 83)): was expecting double-quote to start field name
at [Source: (String)\"{
    \"version\" : \"2017-02-28\",
    \"operation\" : \"Query\",
    \"index\" : \"my-index\",
    \"query\" : {
        \"expression\": \"id IN :ids\",
        \"expressionValues\" : { \":ids\" : {SS=[id1, id2]} }
    },       
    \"limit\": 20,
    \"nextToken\": null
}\"; line: 7, column: 47]'"

It seems OK to use IN for query comparison operator; however, how can I pass a String List as a parameter and fetch the results whose IDs are among those parameters supplied?

EDIT: Corrected variable name typo.


Solution

  • I don't think AWS AppSync support IN just for now. I try to test your scenario and come up with a solution using contains() function.

    enter image description here

    Here is the result after query:

    enter image description here

    Another alternative solution is to use Scan (not recommended)

    {
        "version" : "2017-02-28",
        "operation" : "Scan",
        "filter" : {
            "expression": "contains (:authors, author)",
            "expressionValues" : {
                ":authors" : $util.dynamodb.toDynamoDBJson($ctx.args.authors)
            }
        }
    }
    

    Btw, AWS AppSync support BatchGetItem operation. You can pass a list of keys in a single query and return the results from a table.
    Reference: https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-dynamodb-batch.html
    Here is an example and I tested it worked like charm:

    ## REQUEST MAPPING
    #set($authors = [])
    #foreach( $author in $ctx.args.authors )
        #set($map = {})
        $util.qr($map.put("author", $util.dynamodb.toString($author)))
        $util.qr($authors.add($map))
    #end
    
    {
        "version" : "2018-05-29",
        "operation" : "BatchGetItem",
        "tables" : {
            "tbDiary": {
                "keys": $util.toJson($authors),
                "consistentRead": true
            }
        }
    }
    
    ## RESPONSE MAPPING
    $util.toJson($ctx.result.data.tbDiary)