The opinions expressed on this blog are purely mine

Using DynamoDb Filters and Expression Attribute Names with the aws-go-sdk

2019-01-06

aws-go-sdk documentation doesn’t say much about how to use Expression Attribute Names, or what to do, when one of your attribute names is a reserved word of DynamoDb. Let me fill the hole.

Each examples below are using the Scan API.

Filter by primary partition key

In this basic example, sensorID is the primary partition key.

                  
// Declare ScanInput parameters
// The ones without value will be nil, thus ignored by the request
var expressionAttributeNames map[string]*string
var expressionAttributeValues map[string]*dynamodb.AttributeValue
var filterExpression *string
var projectionExpression *string
// Create an attribute value mapping, so we are able to use :id in the filter expression
expressionAttributeValues = map[string]*dynamodb.AttributeValue{
  ":id": {
        S: aws.String(*SensorID),
  },
}
filterExpression = aws.String("sensorID = :id")

// ProjectionExpression is nil, so we receive all Item attributes in response
params := &dynamodb.ScanInput{
  ExpressionAttributeNames:  expressionAttributeNames,
  ExpressionAttributeValues: expressionAttributeValues,
  FilterExpression:          filterExpression,
  ProjectionExpression:      projectionExpression,
  TableName:                 aws.String(os.Getenv("TABLE_NAME")),
}
results, err := svc.Scan(params)
if err != nil {
  return Response{}, err
}

// Iterate results
for _, i := range results.Items {
  ...
}
                  
                

Filter by primary sort key

In this example, which is basically identical to the previous one, venueID is the primary sort key. I just wanted to demonstrate, that the use of API and parameters is not changing compared to the previous scenario.

                  
// Declare ScanInput parameters
// The ones without value will be nil, thus ignored by the request
var expressionAttributeNames map[string]*string
var expressionAttributeValues map[string]*dynamodb.AttributeValue
var filterExpression *string
var projectionExpression *string

// Create an attribute value mapping, so we are able to use :id in the filter expression
expressionAttributeValues = map[string]*dynamodb.AttributeValue{
  ":v": {
        S: aws.String(*VenueID),
  },
}
filterExpression = aws.String("venueID = :v")

// ProjectionExpression is nil, so we receive all Item attributes in response
params := &dynamodb.ScanInput{
  ExpressionAttributeNames:  expressionAttributeNames,
  ExpressionAttributeValues: expressionAttributeValues,
  FilterExpression:          filterExpression,
  ProjectionExpression:      projectionExpression,
  TableName:                 aws.String(os.Getenv("TABLE_NAME")),
}
results, err := svc.Scan(params)
if err != nil {
  return Response{}, err
}

// Iterate results
for _, i := range results.Items {
  ...
}
                  
                

Filter by primary sort key and arbitrary attribute

Now things are getting exciting. In this example venueID is stays the primary sort key, but we also use state in the expression, which is a keyword reserved by DynamoDb. See the extensive list of reserved keywords here.

                  
// Declare ScanInput parameters
// The ones without value will be nil, thus ignored by the request
var expressionAttributeNames map[string]*string
var expressionAttributeValues map[string]*dynamodb.AttributeValue
var filterExpression *string
var projectionExpression *string

// Create a mapping which replaces "state" word with "#parking_state", so we don't use a reserved word in our expression
expressionAttributeNames = map[string]*string{
  "#parking_state": aws.String("state"),
}

// Create an attribute value mapping, so we are able to use :id in the filter expression
expressionAttributeValues = map[string]*dynamodb.AttributeValue{
  ":v": {
        S: aws.String(*VenueID),
  },
  ":s": {
        N: aws.String(*StateID),
  },
}

// In the expression use "#parking_state" instead of "state"
filterExpression = aws.String("#parking_state = :s AND venueID = :v")

// ProjectionExpression is nil, so we receive all Item attributes in response
params := &dynamodb.ScanInput{
  ExpressionAttributeNames:  expressionAttributeNames,
  ExpressionAttributeValues: expressionAttributeValues,
  FilterExpression:          filterExpression,
  ProjectionExpression:      projectionExpression,
  TableName:                 aws.String(os.Getenv("TABLE_NAME")),
}
results, err := svc.Scan(params)
if err != nil {
  return Response{}, err
}

// Iterate results
for _, i := range results.Items {
  ...
}
                  
                

I hope these snippets will help you write complex Filter Expressions using Go SDK.