Search code examples
javaamazon-web-servicesamazon-dynamodbaws-sdkdynamodb-queries

DynamoDB filterexpression using Contains on a document


I am using Java AWS SDK for AWS dynamoDB. Is it possible to use "Contains" function on a document object? Contains is working on an simple field. but if the field is a @DynamoDBDocument, it is not working. Please let me know if you know of a way to search for a value in a document. My query looks like this:

DynamoDBQueryExpression<SSRequest> query = new DynamoDBQueryExpression<SSRequest>()
            .withHashKeyValues(ssRequest)
            .withIndexName("ssRequestType-index")
            .withFilterExpression(" contains(attachments, :val) ")
            .withExpressionAttributeValues(eav)
            .withConsistentRead(false);

In the above query, attachments is a document. I tried with scan as well. but both scan and query are not working on document fields.


Solution

  • You did not share the structure of your data, but i'll try sum it up:

    {
      "id": "1",
      "val": {
        "ABCLink": [
          {
            "DEFName": "MyDefName1",
            "DEFArn": "DEFArn1"
          },
          {
            "DEFName": "MyDefName2",
            "DEFArn": "DEFArn2"
          }
        ],
        "ABCArn": "ProfileArn1"
      }
    }
    

    Now lets imagine you want all the items where id=1 and val contains DEFArn1

    In order to achieve this you have two options:

    1. You pass the entire map as a condition, meaning you must know both DEFArn and DEFName
        response = client.scan(
            TableName=table_name,
            FilterExpression='contains(#a.#b, :r)',
            ExpressionAttributeValues={
                ':r': {
                    "M": {
                        "DEFName": {
                            "S": "MyDefName1"
                        },
                        "DEFArn": {
                            "S": "DEFArn1"
                        }
                    }
                }
            },
            ExpressionAttributeNames={
                '#a': 'val',
                '#b': 'ABCLink',
            }
        )
    
    1. You do not know the full map, but you know the position it should be in the list:
        response = client.scan(
            TableName=table_name,
            FilterExpression='contains(#a.#b[0].DEFArn, :r)',
            ExpressionAttributeValues={
                ':r': {
                    "S": "DEFArn1"     
                }
            },
            ExpressionAttributeNames={
                '#a': 'val',
                '#b': 'ABCLink',
            }
        )
    

    NOTE: I've reused an example I shared before, and the code is Boto3, but the logic remains the same. I hope it helps your use-case.