希望有人能给我一些启示,我一直在想这个问题。
我在Dynamo中有这个表,我们称之为people
,在这个表中,我有id
的属性作为我们的分区键,name
,lastName
和status
。我希望能够只是更新单个属性或所有的保存ID。现在,我是这样做的。我创建了以下结构体:
type PersonUpdate struct {
FirstName string `json:"firstName,omitempty"`
LastName string `json:"lastName,omitempty"`
Status string `json:"status,omitempty"`
}
来自服务器的请求将只是更新该人的姓氏,所以我们的请求体看起来如下:
{
"lastName": "bob"
}
将请求绑定到结构体后,将发送给dynamo的对象如下所示:
{
"firstName": "",
"lastName": "bob",
"status": "",
}
现在,当你写dynamo的时候,你可以看到,只有一个属性应该更新,而其余的空/null应该被忽略。
执行此操作的代码可以浓缩为以下操作:
// Marshal our object
_, err := dynamodbattribute.MarshalMap(person)
if err != nil{
fmt.Println("some error marshaling")
}
// Create our update input
input := &dynamodb.UpdateItemInput{
key: map[string]*dynamodb.AttributeValue{
"id":{
S: aws.String("1234"),
},
},
TableName: aws.String("people"),
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
":fn": {
S: aws.String(person.FirstName),
},
":ln":{
S: aws.String(person.LastName),
},
":st":{
S: aws.String(person.Status),
},
},
UpdateExpression: aws.String("set firstName = :fn, lastName = :ln, status = :st"),
ReturnValues: aws.String("UPDATED_NEW"),
}
// Send update request to Dynamo
_, err := service.UpdateItem(input)
现在,更新没有问题,问题是firstName
和status
的值为空也被传递了。我试着去看他们的文件,但还是有点困惑。我知道一个事实,Java SDK允许你传递一个名为UPDATE_SKIP_NULL_ATTRIBUTES
的标志,它允许你跳过那些空值,只更新那些有数据的。我不知道在Go中什么是等价的,任何帮助/指导都会很棒。
更新:
尝试使用以下模型:
type UserModel struct {
FirstName string `json:"firstName,omitempty" dynamodbav:"firstName,omitempty"`
LastName string `json:"lastName,omitempty" dynamodbav:"lastName,omitempty"`
}
遵循@jarmod和@fedonev给出的建议。从逻辑上和使用文档可以理解为什么这应该工作,不幸的是,它没有
决定将SDK从V1切换到V2,看看是否可能更新它会有所帮助,虽然我在同一个洞。这是我的更新函数。
update :=expression.Set(expression.Name("firstName"),expression.Value(user.FirstName))
update.Set(expression.Name("lastName"), expression.Value(user.LastName))
expr, err := expression.NewBuilder().WithUpdate(update).Build()
if err != nil {
"log error here..."
}
_, err = svc.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{
TableName: aws.String("people"),
Key: map[string]types.AttributeValue{"id": id},
ExpressionAttributeNames: expr.Names(),
ExpressionAttributeValues: expr.Values(),
UpdateExpression: expr.Update(),
ReturnValues: types.ReturnValueUpdatedNew,
})
if err != nil {
"log error here..."
}
我最终通过编写一个查询和创建函数来解决我的问题,该函数通过我们想要更新的JSON有效负载中的ID进行查询,并根据我们需要更新的内容对查询进行区分,并且任何空字段都被查询结果取代。到目前为止,它解决了我的问题,但我仍然想知道如何去做一个更新使用其预期的功能。
正如@jarmod的注释所说,在封送结构时应用dynamodbav:",omitempty"
标记跳过零值字段:
type PersonUpdate struct {
FirstName string `json:"firstName,omitempty" dynamodbav:",omitempty"`
LastName string `json:"lastName,omitempty" dynamodbav:",omitempty"`
Status string `json:"status,omitempty" dynamodbav:",omitempty"`
}
[Edit: add usage]MarshalMap
现在将忽略零值字段,尊重标签。遍历映射以构造更新表达式:
av, _ := attributevalue.MarshalMap(person)
update := expression.UpdateBuilder{}
for k, v := range av {
update = update.Set(expression.Name(k), expression.Value(v))
}
构建表达式并将其输出传递给UpdateItem
,如op。