在Golang中使用DynamoDB时,如果对query
的调用有更多结果,它将在QueryOutput
上设置LastEvaluatedKey
,然后您可以将其作为ExclusiveStartKey
传递到对query
的下一个调用,以从您停止的地方继续。
当值保留在Golang中时,这非常有效。但是,我正在编写一个分页的API端点,所以我想序列化这个键,这样我就可以将它作为分页令牌交给客户端。类似这样,其中something
是一个神奇的包,它可以完成我想要的任务:
type GetDomainObjectsResponse struct {
Items []MyDomainObject `json:"items"`
NextToken string `json:"next_token"`
}
func GetDomainObjects(w http.ResponseWriter, req *http.Request) {
// ... parse query params, set up dynamoIn ...
dynamoIn.ExclusiveStartKey = something.Decode(params.NextToken)
dynamoOut, _ := db.Query(dynamoIn)
response := GetDomainObjectsResponse{}
dynamodbattribute.UnmarshalListOfMaps(dynamoOut.Items, &response.Items)
response.NextToken := something.Encode(dynamoOut.LastEvaluatedKey)
// ... marshal and write the response ...
}
(请原谅上面的任何错别字,这是我为了隔离问题而快速编写的代码的玩具版本)
因为我需要支持具有不同搜索模式的多个端点,所以我希望有一种方法可以生成不依赖于特定搜索键的分页令牌。
问题是,我还没有找到一个干净和通用的方法来序列化LastEvaluatedKey
。您可以将其直接封送到JSON(然后例如base64编码它以获得令牌),但这样做是不可逆的。LastEvaluatedKey
是map[string]types.AttributeValue
,而types.AttributeValue
是接口,因此虽然json编码器可以读取它,但它不能写入它。
例如,下面的代码在panic: json: cannot unmarshal object into Go value of type types.AttributeValue
时出现异常。
lastEvaluatedKey := map[string]types.AttributeValue{
"year": &types.AttributeValueMemberN{Value: "1993"},
"title": &types.AttributeValueMemberS{Value: "Benny & Joon"},
}
bytes, err := json.Marshal(lastEvaluatedKey)
if err != nil {
panic(err)
}
decoded := map[string]types.AttributeValue{}
err = json.Unmarshal(bytes, &decoded)
if err != nil {
panic(err)
}
我喜欢的是一种直接使用DynamoDB风格的JSON的方法,比如what you get when you run aws dynamodb query
on the CLI。
我想我可以为AttributeValue类型编写自己的序列化器/反序列化器,但这比本项目所需的工作量要大。
有没有人找到一个通用的方法来做到这一点?
2条答案
按热度按时间vsmadaxz1#
好吧,我想明白了。
(再次这是我的真实的解决方案匆忙转移回玩具问题,所以请原谅任何错别字)
正如@buraksurdar所指出的,
attributevalue.Unmarshal
需要一个inteface{}
,结果除了一个具体的类型之外,你还可以传入一个map[string]string
,它就可以工作了。我相信如果
AttributeValue
不是平面的话,这个方法是行不通的,所以这不是一个通用的解决方案。但是我的理解是,从Query
调用返回的LastEvaluatedKey
总是平面的,所以它适用于这个用例。polhcujo2#
受Dan的启发,下面是一个与base64进行序列化和反序列化的解决方案