0

我正在尝试为我拥有的 dynamodb 表创建一个分页端点。但是我已经尝试了一切来让 ExclusiveStartKey 成为正确的类型以使其正常工作。但是,我尝试过的一切似乎都不起作用。

示例代码:

func GetPaginator(tableName string, limit int32, lastEvaluatedKey string) (*dynamodb.ScanPaginator, error) {
    svc, err := GetClient()
    if err != nil {
        logrus.Error(err)
        return nil, err
    }

    input := &dynamodb.ScanInput{
        TableName: aws.String(tableName),
        Limit:     aws.Int32(limit),
    }

    if lastEvaluatedKey != "" {
        input.ExclusiveStartKey = map[string]types.AttributeValue{
            "id": &types.AttributeValueMemberS{
                Value: lastEvaluatedKey,
            },
        }
    }

    paginator := dynamodb.NewScanPaginator(svc, input)
    return paginator, nil
}

编辑:

好的,我正在创建一个需要分页的 API。API 需要有一个查询参数,可以在其中定义 lastEvaluatedId。然后我可以使用 lastEvaluatedId 作为 ScanInput 上的 ExclusiveStartKey 传递。但是,当我这样做时,我仍然从数据库中收到相同的项目。我创建了一个 test.go 文件并将发布以下代码:

package main

import (
    "context"
    "fmt"
    "os"

    "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 PaginateID struct {
    ID string `dynamodbav:"id" json:"id"`
}

func main() {
    lastKey := PaginateID{ID: "ae82a99d-486e-11ec-a7a7-0242ac110002"}

    key, err := attributevalue.MarshalMap(lastKey)
    if err != nil {
        fmt.Println(err)
        return
    }

    cfg, err := config.LoadDefaultConfig(context.TODO(), func(o *config.LoadOptions) error {
        o.Region = os.Getenv("REGION")
        return nil
    })
    if err != nil {
        fmt.Println(err)
        return
    }

    svc := dynamodb.NewFromConfig(cfg, func(o *dynamodb.Options) {
        o.EndpointResolver = dynamodb.EndpointResolverFromURL("http://localhost:8000")
    })

    input := &dynamodb.ScanInput{
        TableName:         aws.String("TABLE_NAME"),
        Limit:             aws.Int32(1),
        ExclusiveStartKey: key,
    }

    paginator := dynamodb.NewScanPaginator(svc, input)

    if paginator.HasMorePages() {
        data, err := paginator.NextPage(context.TODO())
        if err != nil {
            fmt.Println(err)
            return
        }

        fmt.Println(data.Items[0]["id"])
        fmt.Println(data.LastEvaluatedKey["id"])
    }
}

当我运行这个测试代码时。我得到这个输出:

&{ae82a99d-486e-11ec-a7a7-0242ac110002 {}}
&{ae82a99d-486e-11ec-a7a7-0242ac110002 {}}

因此,返回的项目与我传递给 ScanInput.ExclusiveStartKey 的 Id 相同。这意味着它不是从 ExclusiveStartKey 开始的。扫描每次都从头开始。

4

2 回答 2

0

DynamoDBaws-sdk-go-v2查询和扫描分页器构造函数有一个错误(请参阅我的 github 问题,包括修复)。他们不尊重 ExclusiveStartKey 参数。

作为临时修复,我在本地复制了分页器类型,并在构造函数中添加了一行: nextToken: params.ExclusiveStartKey.

于 2021-11-18T15:30:33.057 回答
0

所以基本上你需要做的是获取 LastEvaluatedKey并将其传递给ExclusiveStartKey

您不能使用扫描分页器属性,因为它不是导出属性,因此我建议您通过调用NextPage来使用返回的页面

在以下代码段中,我有一个示例:

func GetPaginator(ctx context.Context,tableName string, limit int32, lastEvaluatedKey map[string]types.AttributeValue) (*dynamodb.ScanOutput, error) {
    svc, err := GetClient()
    if err != nil {
        logrus.Error(err)
        return nil, err
    }

    input := &dynamodb.ScanInput{
        TableName: aws.String(tableName),
        Limit:     aws.Int32(limit),
    }

    if len(lastEvaluatedKey) > 0  {
        input.ExclusiveStartKey = lastEvaluatedKey
    }

    paginator := dynamodb.NewScanPaginator(svc, input)
    
    return paginator.NextPage(), nil
}

请记住,paginator.NextPage(ctx)如果nil没有更多页面,或者您可以使用HasMorePages()

于 2021-11-18T13:31:30.853 回答