Search code examples
gopostaws-lambdaamazon-dynamodbdynamodb-queries

How to fix error with Query dynamodb request?


In DynamoDB I Have a table that contains:

- email (primary key)
- password (attribute)
- rname (attribute)

I'm using V1 of the AWS Go SDK, to implement to perform a query using just the primary key to my database:

My struct to unMarshal to is:

type Item struct {
    Email    string `json:"email"`
    Password string `json:"password"`
    Rname    string `json:"rname"`
}

and the code:

result, err := client.Query(&dynamodb.QueryInput{
        TableName: aws.String("accountsTable"),
        KeyConditions: map[string]*dynamodb.Condition{
            "email": {
                ComparisonOperator: aws.String("EQ"),
                AttributeValueList: []*dynamodb.AttributeValue{
                    {
                        S: aws.String(email),
                    },
                },
            },
        },
    })
    if err != nil {
        return false, err
    }

    item := []Item{}

    err = dynamodbattribute.UnmarshalListOfMaps(result.Items, &item)
    if err != nil {
        return false, err
    }

However, I get the issue that the key is invalid. I check the key in the database and it matches the one i print out to the console too.

Not sure how to get round this issue as example's i've seen seem to work for their's and look the same.

Any help in fixing this issue would be appreciated thanks :)

Table Details


Solution

  • You need to set the values of password and rname to omitempty so that it's not set to empty values as they are not keys they should not be included on a Query as it throws an invalid key exception:

    type Item struct {
        Email    string `json:"email" dynamodbav:"email,omitempty"`
        Password string `json:"password" dynamodbav:"password,omitempty"`
        Rname    string `json:"rname" dynamodbav:"rname,omitempty"`
    }
    

    Update

    I believe the issue is due to the fact you try to marshall the entire response in a single command, however, iterating works for me. (I do not use Go).

    package main
    import (
        "github.com/aws/aws-sdk-go/aws"
        "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"
    
        "fmt"
    )
    
    
    func main() {
    
        // Create Session
        sess := session.Must(session.NewSessionWithOptions(session.Options{
            SharedConfigState: session.SharedConfigEnable,
        }))
    
        // Create DynamoDB Client with Logging
        client := dynamodb.New(sess, aws.NewConfig())
    
    
        type Item struct {
            Email    string `dynamodbav: "email"`
            Password string `dynamodbav: "password,omitempty"`
            Rname    string `dynamodbav: "rname,omitempty"`
        }
    
        result, err := client.Query(&dynamodb.QueryInput{
            TableName: aws.String("accountsTable"),
            KeyConditions: map[string]*dynamodb.Condition{
                "email": {
                    ComparisonOperator: aws.String("EQ"),
                    AttributeValueList: []*dynamodb.AttributeValue{
                        {
                            S: aws.String("lhnng@amazon.com"),
                        },
                    },
                },
            },
        })
    
        if err != nil {
            fmt.Println("Query API call failed:")
            fmt.Println((err.Error()))
        }
    
    
    
        for _, i := range result.Items {
            
            item := Item{}
            err = dynamodbattribute.UnmarshalMap(i, &item)
        
            if err != nil {
                fmt.Println("Got error unmarshalling: %s", err)
            }
        
            fmt.Println("Email: ", item.Email)
            fmt.Println()
            
        }
    }
    

    Moreover, as you use a single key of email, it means there is at most 1 item with the same email address, meaning you should use GetItem rather than Query:

    package main
    
    import (
        "fmt"
    
        "github.com/aws/aws-sdk-go/aws"
        "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"
    )
    
    func main() {
    
        // Item to Get
        type Item struct {
            Email    string `dynamodbav: "email"`
            Password string `dynamodbav: "password,omitempty"`
            Rname    string `dynamodbav: "rname,omitempty"`
        }
    
        // Create Session
        sess := session.Must(session.NewSessionWithOptions(session.Options{
            SharedConfigState: session.SharedConfigEnable,
        }))
    
        // Create DynamoDB Client
        client := dynamodb.New(sess, aws.NewConfig())
    
        // Get Item
        result, err := client.GetItem(&dynamodb.GetItemInput{
            TableName: aws.String("accountsTable"),
            Key: map[string]*dynamodb.AttributeValue{
                "email": {
                    S: aws.String("lhnng@amazon.com"),
                },
            },
        })
    
        // Catch Error
        if err != nil {
            fmt.Println("GetItem API call failed:")
            fmt.Println((err.Error()))
        }
    
        item := Item{}
    
        // Unmarhsall
        err = dynamodbattribute.UnmarshalMap(result.Item, &item)
    
        if err != nil {
            panic(fmt.Sprintf("Failed to unmarshal Record, %v", err))
        }
    
        // If Item Returns Empty
        if item.Email == "" {
            fmt.Println("Could not find Item")
            return
        }
    
        // Print Result
        fmt.Println("Found item:")
        fmt.Println("Email:  ", item.Email)
    
    }