Go でDynamoDBを操作するときguregu/dynamoを使うことも多いが、BatchGetが遅い ことがあったのとaws-sdk-go v1に対応していないので、直接aws-sdk-go-v2を使うことにした
BatchGetするサンプル
BatchGetItemを直接使うサンプルは公式になかったので、PartiQLを使う例を参考にして作ってみた。
aws-doc-sdk-examples/gov2/dynamodb/actions/partiql.go at main · awsdocs/aws-doc-sdk-examples
package dynamo
import (
"context"
"fmt"
"os"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
awsLogging "github.com/aws/smithy-go/logging"
)
type MusicRecord struct {
Artist string
SongTitle string
}
// maxBatchGetItems is max size for one BatchGetItem request
const maxBatchGetItems = 100
func BatchGet(
ctx context.Context,
region string,
endpoint string,
targetTable string,
titles []string,
) ([]MusicRecord, error) {
// initialize client
conf, err := config.LoadDefaultConfig(ctx,
config.WithRegion(region),
config.WithLogger(awsLogging.NewStandardLogger(os.Stdout)),
)
if err != nil {
return nil, fmt.Errorf("unable to load SDK config: %w", err)
}
dynamo := dynamodb.NewFromConfig(conf, func(o *dynamodb.Options) {
if endpoint != "" {
// set endpoint
o.BaseEndpoint = &endpoint
}
})
// create DynamoDB keys
dynamoKeys := make([]map[string]types.AttributeValue, 0)
for _, v := range titles {
dynamoKeys = append(dynamoKeys, map[string]types.AttributeValue{
"SongTitle": &types.AttributeValueMemberS{Value: v},
})
}
chunkedKeys := chunk(dynamoKeys, maxBatchGetItems)
responses := make([]map[string]types.AttributeValue, 0)
for _, k := range chunkedKeys {
// BatchGet value from dynamoDB
input := &dynamodb.BatchGetItemInput{
RequestItems: map[string]types.KeysAndAttributes{
targetTable: {Keys: k},
},
}
out, err := dynamo.BatchGetItem(ctx, input)
if err != nil {
return nil, fmt.Errorf("failed in get items: %w", err)
}
responses = append(responses, out.Responses[targetTable]...)
}
// unmarshal DynamoDB list items to struct
records := []MusicRecord{}
if err := attributevalue.UnmarshalListOfMaps(responses, &records); err != nil {
return nil, fmt.Errorf("failed in unmarshal records: %w", err)
}
return records, nil
}
func chunk[T any](collection []T, chunkSize int) [][]T {
if chunkSize <= 0 {
panic("Second parameter must be greater than 0")
}
result := make([][]T, 0)
for len(collection) > 0 {
if len(collection) < chunkSize {
chunkSize = len(collection)
}
result = append(result, collection[0:chunkSize])
collection = collection[chunkSize:]
}
return result
}