DynamoDB UpdateItem di Go (AWS SDK v2)

UpdateItem cukup lugas di Go; bagian yang canggung adalah map[string]types.AttributeValue merupakan map berisi interface, jadi baik nilai yang Anda kirim maupun yang Anda terima kembali adalah pointer ke salah satu dari sembilan struct anggota. Satu keputusan desain itulah yang menjelaskan sebagian besar gesekan di bawah ini, dimulai dari fakta bahwa fmt.Println di potongan kode ini tidak mencetak item Anda.

Kode

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
}

Penjelasan

  • AttributeValueMemberN.Value bertipe string, bukan tipe numerik, dan attributevalue.Marshal mempertahankannya begitu: int64(9007199254740993) di-marshal menjadi "9007199254740993" persis. Angka DynamoDB membawa presisi 38 digit, lebih dari float Go mana pun, jadi SDK tidak pernah mengonversinya. Andalah yang melakukan parsing, di tepi, secara sadar.

  • ReturnValues: types.ReturnValueAllNew — nilai konstanta itu adalah literal "ALL_NEW". types.ReturnValueAllNew.Values() mendaftar kelimanya (NONE, ALL_OLD, UPDATED_OLD, ALL_NEW, UPDATED_NEW) kalau Anda lebih suka membacanya dari tipenya ketimbang dari dokumentasi.

  • UpdateExpression adalah *string yang Anda bangun sendiri, atau Anda serahkan ke paket expression di bawah. Bagaimanapun, DynamoDB adalah satu-satunya parser: ADD #upd2 :updValue2 memberi penambahan atomik, attribute_exists(Artist) di sebuah ConditionExpression membuat panggilannya hanya-update alih-alih upsert, dan tata bahasa klausanya ada di update expression.

  • ValidationException tidak punya tipe Go. types/errors.go mendefinisikan 35 struct error, termasuk ConditionalCheckFailedException, TransactionCanceledException, ProvisionedThroughputExceededException, dan TransactionConflictException. Kegagalan validasi tidak termasuk di antaranya, jadi expression yang buruk muncul sebagai smithy.APIError generik yang hanya bisa Anda kenali lewat string:

    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: Year

    Perhatikan awalan api error, yang tidak didapat ConditionalCheckFailedException bermodel di bawah. Kehadirannya adalah sinyal yang lumayan bahwa errors.As terhadap tipe konkret tidak akan menolong Anda di sini.

  • Kondisi yang gagal, sebaliknya, adalah tipe sungguhan. var ccf *types.ConditionalCheckFailedException; errors.As(err, &ccf) cocok, dan dengan ReturnValuesOnConditionCheckFailure: types.ReturnValuesOnConditionCheckFailureAllOld pada input, ccf.Item datang terisi item sebagaimana adanya. ccf.ErrorMessage() adalah The conditional request failed yang polos, tanpa pembuka transport yang ditambahkan err.Error() di depannya.

Membaca hasilnya kembali

fmt.Println(out.Attributes) pada map berisi interface mencetak alamat:

map[Artist:0x1c8cf589e060 Awards:0x1c8cf589e078 Genre:0x1c8cf589e090 SongTitle:0x1c8cf589e0c0 Year:0x1c8cf589e0a8]

Ada dua jalan keluar. Lakukan unmarshal ke sebuah struct, yang seharusnya dilakukan kebanyakan kode:

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}

Atau lakukan type assertion pada satu anggota yang Anda pedulikan, dan ingat bahwa .Value adalah string:

n, ok := out.Attributes["Awards"].(*types.AttributeValueMemberN)
if ok {
	awards, _ := strconv.Atoi(n.Value) // "1" -> 1
	fmt.Println(awards)
}

Biarkan paket expression yang menuliskannya

Go adalah satu-satunya SDK di situs ini yang mau membuatkan UpdateExpression untuk Anda. feature/dynamodb/expression menyusun klausa dan kedua map-nya:

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()

Yang keluar bukan yang Anda tulis:

UpdateExpression: ADD #0 :0
SET #1 = :1, #2 = :2

Names: map[#0:Awards #1:Genre #2:Year]

Builder-nya menyusun ulang klausa, memisahkannya dengan baris baru, dan menomori sendiri placeholder-nya, sehingga #0 adalah Awards, bukan nama pertama yang Anda sebut. Tak ada yang di hilir memedulikannya, tetapi string-nya tidak stabil antar-penyuntingan, yang membuatnya buruk untuk dijadikan bahan assert di tes. Oper expr.Update(), expr.Names(), dan expr.Values() langsung ke UpdateItemInput lalu jangan pernah menengoknya lagi.

Sisi baiknya, ia meng-alias setiap nama, sehingga reserved word berhenti menjadi kelas bug yang bisa Anda kirim ke produksi. Kalau Anda menulis expression-nya dengan tangan, lewatkan dulu nama atributnya melalui pemeriksa reserved word DynamoDB — daftar AWS punya 573 entri dan Year, Name, serta Status semuanya ada di sana. Dan kalau Anda lebih suka melihat item sebagai data ketimbang sebagai map berisi pointer interface, unduh DynoTable.

Contoh terkait

Referensi

Terakhir diverifikasi 2026-07-28 terhadap dokumentasi resmi AWS yang ditautkan di atas.

Bekerja dengan DynamoDB tanpa Console

Klien desktop DynamoDB yang cepat dan menjalankan SQL sungguhan yang tidak bisa dijalankan DynamoDB — JOINs, GROUP BY, agregasi — dengan editing visual dan agen AI pada kunci Bedrock milik Anda sendiri.

Uji coba gratis 30 hari, tanpa kartu kredit — lalu paket Free tanpa batas waktu.