Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unmarshal map[string]DynamoDBAttributeValue into a struct

Tags:

I'm trying to set-up an AWS-lambda using aws-sdk-go that is triggered whenever a new user is added to a certain dynamodb table.

Everything is working just fine but I can't find a way to unmarshal a map map[string]DynamoDBAttributeValue like:

{     "name": {         "S" : "John"     },     "residence_address": {         "M": {             "address": {                 "S": "some place"             }         }     } } 

To a given struct, for instance, a User struct. Here is shown an example of unsmarhaling a map[string]*dynamodb.AttributeValue into a given interface, but I can't find a way to do the same thing with map[string]DynamoDBAttributeValue even though these types seem to fit the same purposes.

map[string]DynamoDBAttributeValue is returned by a events.DynamoDBEvents from package github.com/aws/aws-lambda-go/events. This is my code:

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)         }      }  } 

Of course, I can marshal record.Change.NewImage to JSON and unmarshal it back to a given struct, but then, I would have to manually initialize dynamoUser attributes starting from the latter ones.

Or I could even write a function that parses map[string]DynamoDBAttributeValue to map[string]*dynamodb.AttributeValue like:

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 } 

And then simply use dynamodbattribute.UnmarshalMap, but on events.DataTypeMap it would be quite a tricky process.

Is there a way through which I can unmarshal a DynamoDB record coming from a events.DynamoDBEvent into a struct with a similar method shown for map[string]*dynamodb.AttributeValue?

like image 808
AndreaM16 Avatar asked Mar 06 '18 11:03

AndreaM16


1 Answers

I tried the function you provided, and I met some problems with events.DataTypeList, so I managed to write the following function that does the trick:

// 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)  } 
like image 73
Sky.Li Avatar answered Sep 23 '22 16:09

Sky.Li