Dan*_*Dan 6 go amazon-dynamodb
在 Golang 中使用 DynamoDB 时,如果对 的调用query有更多结果,它将LastEvaluatedKey在 上设置QueryOutput,然后您可以将其传递到下一次调用 asquery以ExclusiveStartKey从上次中断的位置继续。
当值保留在 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 ...
}
Run Code Online (Sandbox Code Playgroud)
(请原谅上面的任何拼写错误,这是我为了隔离问题而快速编写的代码的玩具版本)
因为我需要支持具有不同搜索模式的多个端点,所以我希望有一种生成不依赖于特定搜索键的分页标记的方法。
问题是,我还没有找到一种干净且通用的方法来序列化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)
}
Run Code Online (Sandbox Code Playgroud)
我想要的是一种直接使用 DynamoDB 风格的 JSON 的方法,就像在 CLI 上运行时得到的那样aws dynamodb query。不幸的是golang SDK不支持这个。
我想我可以为 AttributeValue 类型编写自己的序列化器/反序列化器,但这比这个项目应有的努力要多。
有没有人找到一个通用的方法来做到这一点?
好吧,我想出了一些办法。
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 ...
eskMap := map[string]string{}
json.Unmarshal(params.NextToken, &eskMap)
esk, _ = dynamodbattribute.MarshalMap(eskMap)
dynamoIn.ExclusiveStartKey = esk
dynamoOut, _ := db.Query(dynamoIn)
response := GetDomainObjectsResponse{}
dynamodbattribute.UnmarshalListOfMaps(dynamoOut.Items, &response.Items)
lek := map[string]string{}
dynamodbattribute.UnmarshalMap(dynamoOut.LastEvaluatedKey, &lek)
response.NextToken := json.Marshal(lek)
// ... marshal and write the response ...
}
Run Code Online (Sandbox Code Playgroud)
(这又是我匆忙转回玩具问题的真正解决方案,所以请原谅任何拼写错误)
正如@buraksurdar 指出的,attributevalue.Unmarshal需要一个inteface{}. 事实证明,除了具体类型之外,您还可以传入map[string]string,并且它就可以工作。
我相信如果不平坦,这将不起作用AttributeValue,所以这不是一个通用的解决方案[需要引用]。但我的理解是,LastEvaluatedKey调用返回的值Query始终是平坦的,因此它适用于这个用例。