新しいuser
が特定の dynamodb に追加されるたびにトリガーされる aws-sdk-go を使用してAWS-lambdaをセットアップしようとしていますテーブル。
すべてうまくいきますが、次のようにマップを非整列化する方法が見つかりませんmap[string]DynamoDBAttributeValue
:
{
"name": {
"S" : "John"
},
"residence_address": {
"M": {
"address": {
"S": "some place"
}
}
}
}
たとえば、特定の構造体、User
構造体。 ここ はmap[string]*dynamodb.AttributeValue
を特定のインターフェイスに非整列化する例を示していますが、これらの型がmap[string]DynamoDBAttributeValue
で同じことを行う方法を見つけることができません同じ目的に適合します。
map[string]DynamoDBAttributeValue
は、パッケージevents.DynamoDBEvents
からgithub.com/aws/aws-lambda-go/events
によって返されます。これは私のコードです:
package handler
import (
"context"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"github.com/aws/aws-sdk-go/service/dynamodb"
)
func HandleDynamoDBRequest(ctx context.Context, e events.DynamoDBEvent) {
for _, record := range e.Records {
if record.EventName == "INSERT" {
// User Struct
var dynamoUser model.DynamoDBUser
// Of course this can't be done for incompatible types
_ := dynamodbattribute.UnmarshalMap(record.Change.NewImage, &dynamoUser)
}
}
}
もちろん、record.Change.NewImage
をJSONにマーシャリングして、アンマーシャリングして特定の構造体に戻すこともできますが、後者の場合はdynamoUser
属性を手動で初期化する必要があります。
または、次のようにmap[string]DynamoDBAttributeValue
をmap[string]*dynamodb.AttributeValue
に解析する関数を書くこともできます。
func getAttributeValueMapFromDynamoDBStreamRecord(e events.DynamoDBStreamRecord) map[string]*dynamodb.AttributeValue {
image := e.NewImage
m := make(map[string]*dynamodb.AttributeValue)
for k, v := range image {
if v.DataType() == events.DataTypeString {
s := v.String()
m[k] = &dynamodb.AttributeValue{
S : &s,
}
}
if v.DataType() == events.DataTypeBoolean {
b := v.Boolean()
m[k] = &dynamodb.AttributeValue{
BOOL : &b,
}
}
// . . .
if v.DataType() == events.DataTypeMap {
// ?
}
}
return m
}
そして、単にdynamodbattribute.UnmarshalMap
を使用しますが、events.DataTypeMap
では非常にトリッキーなプロセスになります。
events.DynamoDBEvent
から取得したDynamoDBレコードをmap[string]*dynamodb.AttributeValue
に示すような同様のメソッドを使用して構造体に非整列化する方法はありますか?
あなたが提供した機能を試しましたが、events.DataTypeList
、だから私はトリックを行う次の関数をなんとか書くことができました:
// UnmarshalStreamImage converts events.DynamoDBAttributeValue to struct
func UnmarshalStreamImage(attribute map[string]events.DynamoDBAttributeValue, out interface{}) error {
dbAttrMap := make(map[string]*dynamodb.AttributeValue)
for k, v := range attribute {
var dbAttr dynamodb.AttributeValue
bytes, marshalErr := v.MarshalJSON(); if marshalErr != nil {
return marshalErr
}
json.Unmarshal(bytes, &dbAttr)
dbAttrMap[k] = &dbAttr
}
return dynamodbattribute.UnmarshalMap(dbAttrMap, out)
}
レコードのNewImageのタイプがmap [string] * dynamodb.AttributeValueではなかったため、dynamodbattributeパッケージを使用できることに不満を感じました。
Events.DynamoDBAttributeValueのJSON表現は、dynamodb.AttributeValueのJSON表現と同じようです。
そこで、独自のDynamoDBEventタイプを作成して、OldImageとNewImageのタイプを変更したので、map [string] events.DynamoDBAttributeValueではなくmap [string] * dynamodb.AttributeValueにマーシャリングしました。
それは少し醜いですが、私にとってはうまくいきます。
package main
import (
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"fmt"
)
func main() {
lambda.Start(lambdaHandler)
}
// changed type of event from: events.DynamoDBEvent to DynamoDBEvent (see below)
func lambdaHandler(event DynamoDBEvent) error {
for _, record := range event.Records {
change := record.Change
newImage := change.NewImage // now of type: map[string]*dynamodb.AttributeValue
var item IdOnly
err := dynamodbattribute.UnmarshalMap(newImage, &item)
if err != nil {
return err
}
fmt.Println(item.Id)
}
return nil
}
type IdOnly struct {
Id string `json:"id"`
}
type DynamoDBEvent struct {
Records []DynamoDBEventRecord `json:"Records"`
}
type DynamoDBEventRecord struct {
AWSRegion string `json:"awsRegion"`
Change DynamoDBStreamRecord `json:"dynamodb"`
EventID string `json:"eventID"`
EventName string `json:"eventName"`
EventSource string `json:"eventSource"`
EventVersion string `json:"eventVersion"`
EventSourceArn string `json:"eventSourceARN"`
UserIdentity *events.DynamoDBUserIdentity `json:"userIdentity,omitempty"`
}
type DynamoDBStreamRecord struct {
ApproximateCreationDateTime events.SecondsEpochTime `json:"ApproximateCreationDateTime,omitempty"`
// changed to map[string]*dynamodb.AttributeValue
Keys map[string]*dynamodb.AttributeValue `json:"Keys,omitempty"`
// changed to map[string]*dynamodb.AttributeValue
NewImage map[string]*dynamodb.AttributeValue `json:"NewImage,omitempty"`
// changed to map[string]*dynamodb.AttributeValue
OldImage map[string]*dynamodb.AttributeValue `json:"OldImage,omitempty"`
SequenceNumber string `json:"SequenceNumber"`
SizeBytes int64 `json:"SizeBytes"`
StreamViewType string `json:"StreamViewType"`
}
当面は、質問で述べた機能を実装することでこの問題を解決することができました。
// May take either `map[string]DynamoDBAttributeValue`
// or `DynamoDBAttributeValue` as input.
func EventStreamToMap(attribute interface{}) map[string]*dynamodb.AttributeValue {
// Map to be returned
m := make(map[string]*dynamodb.AttributeValue)
tmp := make(map[string]events.DynamoDBAttributeValue)
switch t := attribute.(type) {
case map[string]events.DynamoDBAttributeValue:
tmp = t
case events.DynamoDBAttributeValue:
tmp = t.Map()
}
for k, v := range tmp {
switch v.DataType() {
case events.DataTypeString:
s := v.String()
m[k] = &dynamodb.AttributeValue{
S : &s,
}
case events.DataTypeBoolean:
b := v.Boolean()
m[k] = &dynamodb.AttributeValue{
BOOL : &b,
}
// case events.SomeOtherType:
// ...
case events.DataTypeMap:
m[k] = &dynamodb.AttributeValue{
M : EventStreamToMap(v),
}
}
}
return m
}
しかし、私はまだ他の実装を受け入れています。