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.
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 {
  ...
}
                  
                
                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 {
  ...
}
                  
                
                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.