如何从 DynamoDB 的 Golang SDK 序列化`LastEvaluatedKey`?
How to serialize `LastEvaluatedKey` from DynamoDB's Golang SDK?
在 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. Unfortunately the golang SDK doesn't support this.
我想我可以为 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 ...
}
(又是我的真解,草草转回玩具问题,错别字请见谅)
正如@buraksurdar 指出的那样,attributevalue.Unmarshal
需要 inteface{}
。事实证明,除了具体类型之外,您还可以传入一个 map[string]string
,它就可以正常工作。
我相信如果 AttributeValue
不平坦,这将不起作用,因此这不是通用解决方案 [需要引用]。但我的理解是从 Query
调用返回的 LastEvaluatedKey
总是平坦的,所以它适用于这个用例。
在 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. Unfortunately the golang SDK doesn't support this.
我想我可以为 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 ...
}
(又是我的真解,草草转回玩具问题,错别字请见谅)
正如@buraksurdar 指出的那样,attributevalue.Unmarshal
需要 inteface{}
。事实证明,除了具体类型之外,您还可以传入一个 map[string]string
,它就可以正常工作。
我相信如果 AttributeValue
不平坦,这将不起作用,因此这不是通用解决方案 [需要引用]。但我的理解是从 Query
调用返回的 LastEvaluatedKey
总是平坦的,所以它适用于这个用例。