DynamoDB PutItem in Go (AWS SDK v2)
PutItem scrive un Item intero e sostituisce qualsiasi Item esistente con la stessa chiave primaria (azioni basate su Item spiega in cosa differisce da UpdateItem). Nell'AWS SDK for Go v2 la parte interessante non è la chiamata, è cosa diventano i tuoi valori Go lungo la strada.
Codice
package main
import (
"context"
"errors"
"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)
_, err = client.PutItem(ctx, &dynamodb.PutItemInput{
TableName: aws.String("Music"),
Item: map[string]types.AttributeValue{
"Artist": &types.AttributeValueMemberS{Value: "Arturo Sandoval"},
"SongTitle": &types.AttributeValueMemberS{Value: "Cubano Chant"},
"AlbumTitle": &types.AttributeValueMemberS{Value: "Danzon"},
"Year": &types.AttributeValueMemberN{Value: "1994"},
"Awards": &types.AttributeValueMemberN{Value: "0"},
},
ConditionExpression: aws.String("attribute_not_exists(#cond0) AND attribute_not_exists(#cond1)"),
ExpressionAttributeNames: map[string]string{
"#cond0": "Artist",
"#cond1": "SongTitle",
},
})
if err != nil {
var ccf *types.ConditionalCheckFailedException
if errors.As(err, &ccf) {
fmt.Println("A song with that key already exists — not overwritten")
return
}
log.Fatalf("put item: %v", err)
}
fmt.Println("Song written")
}Spiegazione
attributevalue.MarshalMap è la scorciatoia, e ha delle opinioni. Passare una struct a github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue invece di costruire a mano la map[string]types.AttributeValue qui sopra è la mossa normale. Ecco cosa ha prodotto davvero per una struct con un time.Time, un campo string mai toccato e un *int nil:
Artist => &types.AttributeValueMemberS{Value:"Arturo Sandoval"}
SongTitle => &types.AttributeValueMemberS{Value:"Cubano Chant"}
Released => &types.AttributeValueMemberS{Value:"1994-01-01T00:00:00Z"}
Notes => &types.AttributeValueMemberS{Value:""}
Rating => &types.AttributeValueMemberNULL{Value:true}Tre cose da portarsi via. time.Time diventa una stringa RFC 3339, non un numero Unix, quindi una chiave di ordinamento con timestamp ordina lessicograficamente e si comporterà bene solo se ogni valore è riempito con zeri e nello stesso fuso. Una stringa mai toccata diventa un vero attributo stringa vuota invece di essere omessa. E un puntatore nil diventa NULL, che è un attributo che esiste.
Un attributo NULL sconfigge attribute_not_exists. Questo è quello che ti costa un pomeriggio. Scrivi un Item il cui Rating proveniva da un *int nil, poi proteggi la scrittura successiva con attribute_not_exists(Rating) e fallisce:
ConditionalCheckFailedException: The conditional request failedDynamoDB ha ragione: l'attributo c'è, e contiene NULL. La correzione è il tag della struct, dynamodbav:"Rating,omitempty", che elimina il campo invece di annullarlo. Lo stesso tag ferma l'attributo stringa vuota, il che conta perché quelli rompono gli indici sparsi e, in un attributo chiave, vengono rifiutati del tutto:
ValidationException: One or more parameter values are not valid. The AttributeValue for a key attribute cannot contain an empty string value. Key: Artisterrors.As, e mai il confronto tra stringhe. L'SDK Go avvolge ogni errore di servizio nell'operation error di smithy, quindi la stringa che ottieni da err.Error() non è il messaggio che ha inviato DynamoDB:
operation error DynamoDB: PutItem, https response error StatusCode: 400, RequestID: 6886fce0-b246-4762-8a8b-0c6dab813040, ConditionalCheckFailedException: The conditional request failederrors.As(err, &ccf) lo scarta e qui sopra ha restituito true; ccf.ErrorMessage() dà poi il nudo The conditional request failed. Un controllo con strings.Contains sulla stringa esterna funziona oggi e si rompe il giorno in cui l'SDK cambia il formato del suo wrapper.
L'errore tipizzato può portare l'Item che ti ha bloccato. Imposta ReturnValuesOnConditionCheckFailure: types.ReturnValuesOnConditionCheckFailureAllOld sull'input e ccf.Item torna popolato: cinque attributi nell'esecuzione qui sopra, incluso Year come &types.AttributeValueMemberN{Value:"1994"}. Questo ti risparmia il round trip di lettura-dopo-fallimento che la maggior parte dei loop di retry fa a mano. ReturnValues: types.ReturnValueAllOld è l'equivalente sul percorso di successo (ReturnValues).
I numeri sono stringhe, e non è una stranezza di Go. AttributeValueMemberN{Value: "1994"} sembra sbagliato a chiunque venga da un linguaggio tipizzato, ma il tipo N di DynamoDB è un decimale trasportato come testo proprio perché nulla debba passare da un float64. strconv.FormatInt e strconv.FormatFloat sono la conversione; attributevalue la fa per te.
Quello che marshalli è quello che paghi. Un put di un Item da ~15 KB ha riportato "CapacityUnits": 15 con ReturnConsumedCapacity. Le scritture arrotondano per eccesso ogni 1 KB, quindi un campo blob accidentale, o un MarshalMap che ha emesso attributi che volevi scartare, finisce direttamente in bolletta.
Fallo visivamente
Dato che MarshalMap decide cosa finisce davvero nell'Item, vale la pena sapere quanto pesa quell'Item. Il calcolatore della dimensione degli Item DynamoDB gratuito prende il JSON marshalled e restituisce la dimensione in byte e le unità di scrittura a cui arrotonda.
Per scrivere e modificare Item sulle tue tabelle — un form per attributo, selettori di tipo, il risultato ricopiabile come Go — scarica DynoTable.
Esempi correlati
- DynamoDB PutItem in Java — la stessa scrittura condizionale con AWS SDK for Java 2.x, dove un valore non impostato fallisce nel modo opposto.
- DynamoDB UpdateItem in Go — cambia attributi specifici invece di sostituire l'Item.
- Espressioni di condizione DynamoDB —
attribute_not_exists, locking ottimistico e altro. - DynamoDB ConditionalCheckFailedException — cosa lancia la condizione solo-creazione quando l'Item esiste già.
- DynamoDB ValidationException — il contenitore generico per un Item o un'espressione malformati.
Riferimenti
- PutItem — Amazon DynamoDB API Reference
- Use PutItem with an AWS SDK or CLI — Amazon DynamoDB Developer Guide
- dynamodb package — AWS SDK for Go v2 (pkg.go.dev)
- attributevalue package — AWS SDK for Go v2 (pkg.go.dev)
- Handling errors — AWS SDK for Go v2 Developer Guide
- Condition expressions — Amazon DynamoDB Developer Guide
Riprodotto il 2026-07-28 su go1.26.5 con aws-sdk-go-v2/service/dynamodb v1.62.1 e feature/dynamodb/attributevalue v1.20.55, su DynamoDB Local (amazon/dynamodb-local) sulla porta 9000. I valori marshalled, le stringhe di errore e la lettura di capacità sono output catturato, riportato alla lettera.