DynamoDB UpdateItem in Go (AWS SDK v2)
UpdateItem è lineare in Go; la parte scomoda è che map[string]types.AttributeValue è una mappa di interfacce, quindi sia i valori che invii sia quelli che ricevi sono puntatori a una di nove struct membro. Quella singola scelta di design spiega gran parte degli attriti qui sotto, a partire dal fatto che il fmt.Println in questo snippet non stampa il tuo Item.
Codice
package main
import (
"context"
"fmt"
"log"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)
func main() {
ctx := context.TODO()
cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion("us-east-1"))
if err != nil {
log.Fatalf("load config: %v", err)
}
client := dynamodb.NewFromConfig(cfg)
out, err := client.UpdateItem(ctx, &dynamodb.UpdateItemInput{
TableName: aws.String("Music"),
Key: map[string]types.AttributeValue{
"Artist": &types.AttributeValueMemberS{Value: "Arturo Sandoval"},
"SongTitle": &types.AttributeValueMemberS{Value: "Cubano Chant"},
},
UpdateExpression: aws.String("SET #upd0 = :updValue0, #upd1 = :updValue1 ADD #upd2 :updValue2"),
ExpressionAttributeNames: map[string]string{
"#upd0": "Genre",
"#upd1": "Year",
"#upd2": "Awards",
},
ExpressionAttributeValues: map[string]types.AttributeValue{
":updValue0": &types.AttributeValueMemberS{Value: "Latin Jazz"},
":updValue1": &types.AttributeValueMemberN{Value: "1994"},
":updValue2": &types.AttributeValueMemberN{Value: "1"},
},
ReturnValues: types.ReturnValueAllNew,
})
if err != nil {
log.Fatalf("update item: %v", err)
}
fmt.Println(out.Attributes) // the item after the update
}Spiegazione
AttributeValueMemberN.Valueè unastring, non un tipo numerico, eattributevalue.Marshalla lascia tale:int64(9007199254740993)viene marshallato in"9007199254740993"esattamente. I numeri DynamoDB portano 38 cifre di precisione, più di qualsiasi float Go, quindi l'SDK non converte mai. Il parsing lo fai tu, al confine, deliberatamente.ReturnValues: types.ReturnValueAllNew— il valore della costante è il letterale"ALL_NEW".types.ReturnValueAllNew.Values()elenca tutte e cinque (NONE,ALL_OLD,UPDATED_OLD,ALL_NEW,UPDATED_NEW) se preferisci leggerle dal tipo invece che dalla documentazione.UpdateExpressionè un*stringche costruisci tu, o che deleghi al pacchettoexpressionpiù sotto. In entrambi i casi DynamoDB è l'unico parser:ADD #upd2 :updValue2dà l'incremento atomico,attribute_exists(Artist)in unaConditionExpressionrende la chiamata di solo aggiornamento invece che un upsert, e la grammatica delle clausole vive in update expressions.ValidationExceptionnon ha un tipo Go.types/errors.godefinisce 35 struct di errore, tra cuiConditionalCheckFailedException,TransactionCanceledException,ProvisionedThroughputExceededExceptioneTransactionConflictException. I fallimenti di validazione non sono tra questi, quindi un'espressione sbagliata emerge come un genericosmithy.APIErrorche puoi riconoscere solo dalla stringa:operation error DynamoDB: UpdateItem, https response error StatusCode: 400, RequestID: 702d67f1-4f15-43dc-b3e9-cea691878801, api error ValidationException: Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: YearNota il prefisso
api error, che la modellataConditionalCheckFailedExceptionqui sotto non riceve. La sua presenza è un buon segnale cheerrors.Ascontro un tipo concreto non ti aiuterà qui.Una condizione fallita, al contrario, è un tipo vero.
var ccf *types.ConditionalCheckFailedException; errors.As(err, &ccf)corrisponde, e conReturnValuesOnConditionCheckFailure: types.ReturnValuesOnConditionCheckFailureAllOldsull'input,ccf.Itemarriva popolato con l'Item com'era davvero.ccf.ErrorMessage()è il nudoThe conditional request failed, senza il preambolo di trasporto cheerr.Error()antepone.
Rileggere il risultato
fmt.Println(out.Attributes) su una mappa di interfacce stampa indirizzi:
map[Artist:0x1c8cf589e060 Awards:0x1c8cf589e078 Genre:0x1c8cf589e090 SongTitle:0x1c8cf589e0c0 Year:0x1c8cf589e0a8]Due vie d'uscita. Fai l'unmarshal in una struct, che è ciò che la maggior parte del codice dovrebbe fare:
var song struct {
Artist string
Genre string
Year int
Awards int
}
err = attributevalue.UnmarshalMap(out.Attributes, &song)
// {Artist:Arturo Sandoval Genre:Latin Jazz Year:1994 Awards:1}Oppure fai un'asserzione sull'unico membro che ti interessa, e ricorda che .Value è una stringa:
n, ok := out.Attributes["Awards"].(*types.AttributeValueMemberN)
if ok {
awards, _ := strconv.Atoi(n.Value) // "1" -> 1
fmt.Println(awards)
}Lascia che sia il pacchetto expression a scriverla
Go è l'unico SDK su questo sito che genererà l'UpdateExpression al posto tuo. feature/dynamodb/expression compone le clausole ed entrambe le mappe:
upd := expression.Set(expression.Name("Genre"), expression.Value("Latin Jazz")).
Set(expression.Name("Year"), expression.Value(1994)).
Add(expression.Name("Awards"), expression.Value(1))
expr, _ := expression.NewBuilder().WithUpdate(upd).Build()Quello che esce non è quello che hai scritto:
UpdateExpression: ADD #0 :0
SET #1 = :1, #2 = :2
Names: map[#0:Awards #1:Genre #2:Year]Il builder ha riordinato le clausole, le ha separate con un a capo e ha numerato da sé i placeholder, quindi #0 è Awards e non il primo nome che hai menzionato. A valle non importa a nessuno, ma le stringhe non sono stabili tra una modifica e l'altra, il che le rende una pessima cosa su cui fare asserzioni nei test. Passa expr.Update(), expr.Names() ed expr.Values() direttamente in UpdateItemInput e non guardarle mai.
Il lato positivo è che mette un alias su ogni nome, quindi le parole riservate smettono di essere una classe di bug che puoi spedire. Se invece scrivi l'espressione a mano, passa prima i nomi degli attributi per il controllo delle parole riservate DynamoDB — la lista AWS ha 573 voci e Year, Name e Status ci sono tutte. E se preferisci guardare un Item come dati invece che come una mappa di puntatori a interfacce, scarica DynoTable.
Esempi correlati
- DynamoDB UpdateItem in Java — lo stesso aggiornamento con AWS SDK for Java 2.x.
- DynamoDB PutItem in Go — sostituisci invece l'Item intero.
- Update expressions DynamoDB —
SET,ADD,REMOVE,DELETEe gli idiomi. - Capire ReturnValues — cosa ti dà ciascuna opzione di
ReturnValues. - "Attribute name is a reserved keyword" — perché la mappa di alias qui non è opzionale.
- Errori di sintassi "Invalid UpdateExpression" — i comuni errori di sintassi SET/ADD, decodificati.
Riferimenti
- UpdateItem — Amazon DynamoDB API Reference
- Use UpdateItem with an AWS SDK or CLI — Amazon DynamoDB Developer Guide
- dynamodb package — AWS SDK for Go v2 (pkg.go.dev)
- dynamodb/types package — AWS SDK for Go v2 (pkg.go.dev)
- expression package — AWS SDK for Go v2 (pkg.go.dev)
- Update expressions — Amazon DynamoDB Developer Guide
Ultima verifica 2026-07-28 rispetto alla documentazione ufficiale AWS collegata sopra.