在GO Lambda中处理DynamoDB项

huangapple go评论72阅读模式
英文:

Processing DynamoDB Items in GO Lambda

问题

我正在执行一个简单的表扫描操作,从我的DynamoDB表products中获取所有项目。以下是完整的Lambda代码:

package main

import (
	"context"
	"fmt"

	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb"
)

type Product struct {
	productUUID string
	name        string
	description string
	brand       string
	price       string
	category    string
	dateAdded   string
}

func handleRequest() (string, error) {
	cfg, err := config.LoadDefaultConfig(context.TODO(), func(o *config.LoadOptions) error {
		o.Region = "us-east-2"
		return nil
	})

	if err != nil {
		panic(err)
	}

	svc := dynamodb.NewFromConfig(cfg)

	out, err := svc.Scan(context.TODO(), &dynamodb.ScanInput{
		TableName: aws.String("products"),
	})

	if err != nil {
		panic(err)
	}

	var products []Product

	for _, item := range out.Items {
		product := Product{
			productUUID: aws.ToString(item["productUUID"].S),
			name:        aws.ToString(item["name"].S),
			description: aws.ToString(item["description"].S),
			brand:       aws.ToString(item["brand"].S),
			price:       aws.ToString(item["price"].S),
			category:    aws.ToString(item["category"].S),
			dateAdded:   aws.ToString(item["dateAdded"].S),
		}

		products = append(products, product)
	}

	return "Items", nil // 临时调试返回值(始终为200)。我想在这里返回一个json对象
}

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

当我获取数据后,我可以按以下形式打印出每个项目:

map[brand:0xc0002f38a8 category:0xc0002f3848 dateAdded:0xc0002f3830 name:0xc0002f3800 price:0xc0002f37a0 productUUID:0xc0002f3818]

我该如何将这些项目转换为我上面定义的结构体,并返回Lambda期望的json响应(基本上是一个HTTP响应代码和以json形式表示的项目)?

英文:

I'm performing a simple table Scan to get all items from my DynamoDB table, products. Here is the whole Lambda:

package main

import (
	"context"
	"fmt"

	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb"
)

type Product struct {
	productUUID string
	name        string
	description string
	brand       string
	price       string
	category    string
	dateAdded   string
}

func handleRequest() (string, error) {
	cfg, err := config.LoadDefaultConfig(context.TODO(), func(o *config.LoadOptions) error {
		o.Region = "us-east-2"
		return nil
	})

	if err != nil {
		panic(err)
	}

	svc := dynamodb.NewFromConfig(cfg)

	out, err := svc.Scan(context.TODO(), &dynamodb.ScanInput{
		TableName: aws.String("products"),
	})

	if err != nil {
		panic(err)
	}

	for _, item := range out.Items {
		fmt.Println(item)
	}

	return "Items", nil // Temporary debugging return (always 200). I'd like to return a json object here
}

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

When I get the data back, I can print out each item in the following form:

map[brand:0xc0002f38a8 category:0xc0002f3848 dateAdded:0xc0002f3830 name:0xc0002f3800 price:0xc0002f37a0 productUUID:0xc0002f3818]

How can I convert these Items into the struct I defined above, and then return the json response that is expected from lambda (basically an HTTP response code and the Items in json form)?

答案1

得分: 1

扫描表格返回项目的映射,你想将映射转换为结构体,为了将映射列表转换为结构体,你可以使用 aws-sdk-go-v2 中的 attributevalue.UnmarshalListOfMaps。在之前的版本中,它位于 dynamodbattribute,但他们决定在 v2 版本中更改包。

products := []Product{}
err = attributevalue.UnmarshalListOfMaps(out.Items, &products)
if err != nil {
    panic(fmt.Sprintf("failed to unmarshal Dynamodb Scan Items, %v", err))
}

productsJson, err := json.Marshal(products)
if err != nil {
    panic(err)
}

我在 Product 结构体中看到一个问题,你需要使用导出的字段名,并为结构体字段定义 json 标签,否则数据将无法解组到结构体中。因此,为了将表格的扫描项返回到 JSON 响应中,你的代码应该如下所示。

package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/aws/aws-sdk-go-v2/aws"
    "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"
)

type Product struct {
    ProductUUID string `json:"productUUID"`
    Name        string `json:"name"`
    Description string `json:"description"`
    Brand       string `json:"brand"`
    Price       string `json:"price"`
    Category    string `json:"category"`
    DateAdded   string `json:"dateAdded"`
}

func handleRequest() (events.APIGatewayProxyResponse, error) {
    products := []Product{}
    cfg, err := config.LoadDefaultConfig(context.TODO(), func(o *config.LoadOptions) error {
        o.Region = "us-east-2"
        return nil
    })

    if err != nil {
        panic(err)
    }
    svc := dynamodb.NewFromConfig(cfg)

    out, err := svc.Scan(context.TODO(), &dynamodb.ScanInput{
        TableName: aws.String("products"),
    })

    if err != nil {
        panic(err)
    }

    err = attributevalue.UnmarshalListOfMaps(out.Items, &products)
    if err != nil {
        panic(fmt.Sprintf("failed to unmarshal Dynamodb Scan Items, %v", err))
    }

    productsJson, err := json.Marshal(products)
    if err != nil {
        panic(err)
    }

    resp := events.APIGatewayProxyResponse{
        StatusCode:      200,
        IsBase64Encoded: false,
        Body:            string(productsJson),
        Headers: map[string]string{
            "Content-Type": "application/json",
        },
    }

    return resp, nil
}

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

P.S.:
扫描整个 DynamoDB 表并将其作为响应返回是非常昂贵的,你应该避免这样做。

英文:

Scanning the table returns the map of items and you want to convert map into the struct so in order to convert the list of maps to the struct you want to use attributevalue.UnmarshalListOfMaps under aws-sdk-go-v2. In the previous version it was in the dynamodbattribute but they decided to change the package in the v2.

products := []Product{}
err = attributevalue.UnmarshalListOfMaps(out.Items, &products)
if err != nil {
	panic(fmt.Sprintf("failed to unmarshal Dynamodb Scan Items, %v", err))
}

productsJson, err := json.Marshal(products)
if err != nil {
	panic(err)
}

One problem I saw in the Product struct is that you need to use exported names and also need to define json tags for the struct fields otherwise the data would not be unmarshalled to the structs. So in order to return the scan items from the tables into the json response your code should look like this.


package main

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go-v2/aws"
	"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"
)

type Product struct {
	ProductUUID string `json:"productUUID"`
	Name        string `json:"name"`
	Description string `json:"description"`
	Brand       string `json:"brand"`
	Price       string `json:"price"`
	Category    string `json:"category"`
	DateAdded   string `json:"dateAdded"`
}

func handleRequest() (events.APIGatewayProxyResponse, error) {
	products := []Product{}
	cfg, err := config.LoadDefaultConfig(context.TODO(), func(o *config.LoadOptions) error {
		o.Region = "us-east-2"
		return nil
	})

	if err != nil {
		panic(err)
	}
	svc := dynamodb.NewFromConfig(cfg)

	out, err := svc.Scan(context.TODO(), &dynamodb.ScanInput{
		TableName: aws.String("products"),
	})

	if err != nil {
		panic(err)
	}

	err = attributevalue.UnmarshalListOfMaps(out.Items, &products)
	if err != nil {
		panic(fmt.Sprintf("failed to unmarshal Dynamodb Scan Items, %v", err))
	}

	productsJson, err := json.Marshal(products)
	if err != nil {
		panic(err)
	}

	resp := events.APIGatewayProxyResponse{
		StatusCode:      200,
		IsBase64Encoded: false,
		Body:            string(productsJson),
		Headers: map[string]string{
			"Content-Type": "application/json",
		},
	}

	return resp, nil
}

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

P.S:
Scanning the whole dynamo table and returning it as a response is very costly and you should avoid it.

huangapple
  • 本文由 发表于 2022年4月3日 23:41:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/71727437.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定