英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论