dynamodbattribute.MarshalMap returns empty map
Asked Answered
J

2

7

I'm attempting to write a really simple Go function to insert an entry into a DynamoDB table.

I'm following the tutorial provided on the AWS Documentation site, but for some reason, the function dynamodbattribute.MarshalMap is returning an empty map.

The code compiles and runs, but breaks when attempting to insert the record as it can't find the required keys in the map. A little println action shows that the map is empty, even though the struct it's created from isn't.

Any help is appreciated!

package main

import (
    "context"
    "fmt"

    "github.com/aws/aws-sdk-go/aws"

    "github.com/aws/aws-lambda-go/lambda"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/dynamodb"
    "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)

// Item Struct for Fruit Item
type Item struct {
    fruitID   int
    fruitName string
}

/*HandleRequest handles the lambda request.*/
func HandleRequest(ctx context.Context) (string, error) {
    // Initialize a session that the SDK will use to load
    // credentials from the shared credentials file ~/.aws/credentials
    // and region from the shared configuration file ~/.aws/config.
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        SharedConfigState: session.SharedConfigEnable,
    }))

    // Create DynamoDB client
    svc := dynamodb.New(sess)

    item := Item{
        fruitID:   2,
        fruitName: "Orange",
    }

    fmt.Println(item)

    av, err := dynamodbattribute.MarshalMap(item)
    if err != nil {
        fmt.Println("Got error marshalling new fruit item: ")
        fmt.Println(err.Error())
        return "", err
    }

    fmt.Println("av: ", av)
    fmt.Println("ln: ", len(av))
    fmt.Println("KEY VALUE PAIRS::")
    for key, value := range av {
        fmt.Println("Key:", key, "Value:", value)
    }

    tableName := "fruits"

    input := &dynamodb.PutItemInput{
        Item:      av,
        TableName: aws.String(tableName),
    }

    _, err = svc.PutItem(input)
    if err != nil {
        fmt.Println("Got error inserting new fruit item: ")
        fmt.Println(err.Error())
        return "", err
    }

    return "SUCCESS!", nil
}

func main() {
    lambda.Start(HandleRequest)
}

Log output from Lambda

START RequestId: 82f120d9-6bba-40d9-9204-136d491dbb88 Version: $LATEST
{2 Orange}
av:  map[]
ln:  0
KEY VALUE PAIRS::
Got error inserting new fruit item: 
ValidationException: One or more parameter values were invalid: Missing the key fruitId in the item
    status code: 400, request id: QUJG8R8EHPO65O1JFVI98PRQ1VVV4KQNSO5AEMVJF66Q9ASUAAJG
ValidationException: One or more parameter values were invalid: Missing the key fruitId in the item
    status code: 400, request id: QUJG8R8EHPO65O1JFVI98PRQ1VVV4KQNSO5AEMVJF66Q9ASUAAJG: requestError
null
END RequestId: 82f120d9-6bba-40d9-9204-136d491dbb88
Johnnyjohnnycake answered 2/12, 2019 at 14:16 Comment(0)
B
8

The fields in struct starts with Capital letter is only exported and can be used in outside of this package.

Can you try with this struct and see if that works ?

type Item struct {
    FruitID   int
    FruitName string
}
Bernstein answered 2/12, 2019 at 14:41 Comment(1)
This should be the approved answer, the fields need to be exported, so start with a capitol letter.Nurse
C
2

In order for fields to be exported from a struct, they must start with a capital letter. In order to therefore get the struct fields to match your DynamoDB field names, you can do this:

type Item struct {
    FruitID   int    `dynamodbav:"fruitID"`
    FruitName string `dynamodbav:"fruitName"`
}

The Marshal function will use the labels indicated (fruitID instead of FruitID, etc). I found that using json labels didn't work for me, whereas dynamodbav did.

Cloistered answered 27/2, 2023 at 18:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.