

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# Bekerja dengan tabel, item, kueri, pindaian, dan indeks
<a name="WorkingWithDynamo"></a>

Bagian ini menyediakan detail tentang bekerja dengan tabel, item, kueri, dan banyak lagi di Amazon DynamoDB.

**Topics**
+ [Bekerja dengan tabel dan data di DynamoDB](WorkingWithTables.md)
+ [Tabel global - multi-aktif, replikasi Multi-wilayah](GlobalTables.md)
+ [Bekerja dengan item dan atribut di DynamoDB](WorkingWithItems.md)
+ [Meningkatkan akses data dengan indeks sekunder di DynamoDB](SecondaryIndexes.md)
+ [Mengelola alur kerja kompleks dengan DynamoDB Transactions](transactions.md)
+ [Tangkapan data perubahan dengan Amazon DynamoDB](streamsmain.md)

# Bekerja dengan tabel dan data di DynamoDB
<a name="WorkingWithTables"></a>

Bagian ini menjelaskan cara menggunakan AWS Command Line Interface (AWS CLI) dan AWS SDKs untuk membuat, memperbarui, dan menghapus tabel di Amazon DynamoDB.

**catatan**  
Anda juga dapat melakukan tugas-tugas yang sama ini menggunakan Konsol Manajemen AWS. Untuk informasi selengkapnya, lihat [Menggunakan konsol](AccessingDynamoDB.md#ConsoleDynamoDB).

Bagian ini juga menyediakan informasi selengkapnya tentang kapasitas throughput menggunakan penskalaan otomatis DynamoDB atau mengatur throughput yang disediakan secara manual.

**Topics**
+ [Operasi dasar pada tabel DynamoDB](WorkingWithTables.Basics.md)
+ [Pertimbangan saat memilih kelas tabel di DynamoDB](WorkingWithTables.tableclasses.md)
+ [Menambahkan tag dan label ke sumber daya di DynamoDB](Tagging.md)

# Operasi dasar pada tabel DynamoDB
<a name="WorkingWithTables.Basics"></a>

Mirip dengan sistem basis data lainnya, Amazon DynamoDB menyimpan data dalam tabel. Anda dapat mengelola tabel Anda menggunakan beberapa operasi dasar.

**Topics**
+ [Membuat tabel](#WorkingWithTables.Basics.CreateTable)
+ [Menjelaskan tabel](#WorkingWithTables.Basics.DescribeTable)
+ [Memperbarui tabel](#WorkingWithTables.Basics.UpdateTable)
+ [Menghapus tabel](#WorkingWithTables.Basics.DeleteTable)
+ [Menggunakan perlindungan penghapusan](#WorkingWithTables.Basics.DeletionProtection)
+ [Mencantumkan nama tabel](#WorkingWithTables.Basics.ListTables)
+ [Menggambarkan kuota throughput yang disediakan](#WorkingWithTables.Basics.DescribeLimits)

## Membuat tabel
<a name="WorkingWithTables.Basics.CreateTable"></a>

Gunakan operasi `CreateTable` untuk membuat tabel di Amazon DynamoDB. Untuk membuat tabel, Anda harus memberikan informasi berikut:
+ **Nama tabel.** Nama harus sesuai dengan aturan penamaan DynamoDB, dan harus unik untuk akun saat ini dan Wilayah. AWS Misalnya, Anda dapat membuat tabel `People` di AS Timur (Virginia Utara) dan tabel `People` lainnya di Eropa (Irlandia). Namun, kedua tabel ini akan benar-benar berbeda satu sama lain. Untuk informasi selengkapnya, lihat [Jenis data dan aturan penamaan yang didukung di Amazon DynamoDB](HowItWorks.NamingRulesDataTypes.md).
+ **Kunci primer.** Kunci primer dapat terdiri dari satu atribut (kunci partisi) atau dua atribut (kunci partisi dan kunci urutan). Anda perlu memberikan nama atribut, jenis daya, dan peran dari masing-masing atribut: `HASH` (untuk kunci partisi) dan `RANGE` (untuk kunci urutan). Untuk informasi selengkapnya, lihat [Kunci primer](HowItWorks.CoreComponents.md#HowItWorks.CoreComponents.PrimaryKey).
+ **Pengaturan throughput (untuk tabel yang disediakan).** Jika menggunakan mode yang disediakan, Anda harus menentukan pengaturan throughput tulis dan baca awal untuk tabel. Anda dapat mengubah pengaturan ini di waktu lain, atau mengaktifkan penskalaan otomatis DynamoDB untuk mengelola pengaturan untuk Anda. Untuk informasi selengkapnya, lihat [DynamoDB menyediakan mode kapasitas](provisioned-capacity-mode.md) dan [Mengelola kapasitas throughput secara otomatis dengan penskalaan otomatis DynamoDB](AutoScaling.md).

### Contoh 1: Buat tabel sesuai permintaan
<a name="create-payperrequest-example"></a>

Untuk membuat tabel `Music` yang sama menggunakan mode sesuai permintaan.

```
aws dynamodb create-table \
    --table-name Music \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --billing-mode=PAY_PER_REQUEST
```

Operasi `CreateTable` mengembalikan metadata untuk tabel, seperti yang ditunjukkan berikut ini.

```
{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:us-east-1:123456789012:table/Music",
        "AttributeDefinitions": [
            {
                "AttributeName": "Artist",
                "AttributeType": "S"
            },
            {
                "AttributeName": "SongTitle",
                "AttributeType": "S"
            }
        ],
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "WriteCapacityUnits": 0,
            "ReadCapacityUnits": 0
        },
        "TableSizeBytes": 0,
        "TableName": "Music",
        "BillingModeSummary": {
            "BillingMode": "PAY_PER_REQUEST"
        },
        "TableStatus": "CREATING",
        "TableId": "12345678-0123-4567-a123-abcdefghijkl",
        "KeySchema": [
            {
                "KeyType": "HASH",
                "AttributeName": "Artist"
            },
            {
                "KeyType": "RANGE",
                "AttributeName": "SongTitle"
            }
        ],
        "ItemCount": 0,
        "CreationDateTime": 1542397468.348
    }
}
```

**penting**  
 Ketika memanggil `DescribeTable` pada tabel sesuai permintaan, unit kapasitas baca dan unit kapasitas tulis ditetapkan ke 0. 

### Contoh 2: Buat tabel yang disediakan
<a name="create-provisioned-example"></a>

 AWS CLI Contoh berikut menunjukkan cara membuat tabel (`Music`). Kunci primer terdiri dari `Artist` (kunci partisi) dan `SongTitle` (kunci urutan), masing-masing memiliki jenis daya `String`. Throughput maksimum untuk tabel ini adalah 10 unit kapasitas baca dan 5 unit kapasitas tulis.

```
aws dynamodb create-table \
    --table-name Music \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5
```

Operasi `CreateTable` mengembalikan metadata untuk tabel, seperti yang ditunjukkan berikut ini.

```
{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:us-east-1:123456789012:table/Music",
        "AttributeDefinitions": [
            {
                "AttributeName": "Artist",
                "AttributeType": "S"
            },
            {
                "AttributeName": "SongTitle",
                "AttributeType": "S"
            }
        ],
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "WriteCapacityUnits": 5,
            "ReadCapacityUnits": 10
        },
        "TableSizeBytes": 0,
        "TableName": "Music",
        "TableStatus": "CREATING",
        "TableId": "12345678-0123-4567-a123-abcdefghijkl",
        "KeySchema": [
            {
                "KeyType": "HASH",
                "AttributeName": "Artist"
            },
            {
                "KeyType": "RANGE",
                "AttributeName": "SongTitle"
            }
        ],
        "ItemCount": 0,
        "CreationDateTime": 1542397215.37
    }
}
```

Elemen `TableStatus` menunjukkan status tabel saat ini (`CREATING`). Mungkin perlu beberapa saat untuk membuat tabel, bergantung pada nilai yang Anda tentukan untuk `ReadCapacityUnits` dan `WriteCapacityUnits`. Nilai yang lebih besar untuk ini memerlukan DynamoDB mengalokasikan lebih banyak sumber daya untuk tabel.

### Contoh 3: Membuat tabel menggunakan kelas tabel akses standar-jarang DynamoDB
<a name="create-infrequent-access-example"></a>

Untuk membuat tabel `Music` yang sama menggunakan kelas tabel akses standar-jarang DynamoDB.

```
aws dynamodb create-table \
    --table-name Music \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5 \
    --table-class STANDARD_INFREQUENT_ACCESS
```

Operasi `CreateTable` mengembalikan metadata untuk tabel, seperti yang ditunjukkan berikut ini.

```
{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:us-east-1:123456789012:table/Music",
        "AttributeDefinitions": [
            {
                "AttributeName": "Artist",
                "AttributeType": "S"
            },
            {
                "AttributeName": "SongTitle",
                "AttributeType": "S"
            }
        ],
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "WriteCapacityUnits": 5,
            "ReadCapacityUnits": 10
        },
        "TableClassSummary": {
            "LastUpdateDateTime": 1542397215.37,
            "TableClass": "STANDARD_INFREQUENT_ACCESS"
        },
        "TableSizeBytes": 0,
        "TableName": "Music",
        "TableStatus": "CREATING",
        "TableId": "12345678-0123-4567-a123-abcdefghijkl",
        "KeySchema": [
            {
                "KeyType": "HASH",
                "AttributeName": "Artist"
            },
            {
                "KeyType": "RANGE",
                "AttributeName": "SongTitle"
            }
        ],
        "ItemCount": 0,
        "CreationDateTime": 1542397215.37
    }
}
```

## Menjelaskan tabel
<a name="WorkingWithTables.Basics.DescribeTable"></a>

Untuk melihat detail tentang tabel, gunakan operasi `DescribeTable`. Anda harus memberikan nama tabel. Output dari `DescribeTable` adalah dalam format yang sama seperti dari `CreateTable`. Ini mencakup stempel waktu pembuatan tabel, skema kunci, pengaturan throughput yang disediakan, perkiraan ukuran, dan indeks sekunder apa pun yang ada.

**penting**  
 Ketika menjalankan `DescribeTable` pada tabel sesuai permintaan, unit kapasitas baca dan unit kapasitas tulis ditetapkan ke 0. 

**Example**  

```
aws dynamodb describe-table --table-name Music
```

Tabel siap digunakan ketika `TableStatus` berubah dari `CREATING` menjadi `ACTIVE`.

**catatan**  
Jika Anda mengeluarkan permintaan `DescribeTable` segera setelah permintaan `CreateTable`, DynamoDB mungkin mengembalikan kesalahan (`ResourceNotFoundException`). Hal ini karena `DescribeTable` menggunakan kueri yang akhirnya konsisten, dan metadata untuk tabel Anda mungkin tidak tersedia pada saat itu. Tunggu selama beberapa detik, kemudian coba permintaan `DescribeTable` kembali.  
Untuk tujuan penagihan, biaya penyimpanan DynamoDB mencakup overhead per item sebesar 100 byte. (Untuk informasi selengkapnya, buka [Harga DynamoDB](https://aws.amazon.com/dynamodb/pricing/).) Tambahan 100 byte per item ini tidak digunakan dalam perhitungan unit kapasitas atau oleh operasi `DescribeTable`. 

## Memperbarui tabel
<a name="WorkingWithTables.Basics.UpdateTable"></a>

Operasi `UpdateTable` memungkinkan Anda melakukan salah satu hal berikut:
+ Memodifikasi pengaturan throughput tabel yang disediakan (untuk tabel mode yang disediakan).
+ Ubah mode read/write kapasitas tabel.
+ Memanipulasi indeks sekunder global pada tabel (lihat [Menggunakan Indeks Sekunder Global di DynamoDB](GSI.md)).
+ Mengaktifkan atau menonaktifkan DynamoDB Streams pada tabel (lihat [Tangkapan data perubahan DynamoDB Streams](Streams.md)).

**Example**  
 AWS CLI Contoh berikut menunjukkan cara memodifikasi pengaturan throughput disediakan tabel.  

```
aws dynamodb update-table --table-name Music \
    --provisioned-throughput ReadCapacityUnits=20,WriteCapacityUnits=10
```

**catatan**  
Ketika Anda mengeluarkan permintaan `UpdateTable`, status tabel berubah dari `AVAILABLE` menjadi `UPDATING`. Tabel tetap sepenuhnya tersedia untuk digunakan saat `UPDATING`. Setelah proses ini selesai, status tabel berubah dari `UPDATING` menjadi `AVAILABLE`.

**Example**  
 AWS CLI Contoh berikut menunjukkan cara memodifikasi mode read/write kapasitas tabel ke mode on-demand.  

```
aws dynamodb update-table --table-name Music \
    --billing-mode PAY_PER_REQUEST
```

## Menghapus tabel
<a name="WorkingWithTables.Basics.DeleteTable"></a>

Anda dapat menghapus tabel yang tidak digunakan dengan operasi `DeleteTable`. Menghapus tabel adalah operasi yang tidak dapat dipulihkan. Untuk menghapus tabel menggunakan Konsol Manajemen AWS, lihat[Langkah 6: (Opsional) Hapus tabel DynamoDB Anda untuk membersihkan sumber daya](getting-started-step-6.md).

**Example**  
 AWS CLI Contoh berikut menunjukkan cara menghapus tabel.  

```
aws dynamodb delete-table --table-name Music
```

Ketika Anda mengeluarkan permintaan `DeleteTable`, status tabel berubah dari `ACTIVE` menjadi `DELETING`. Mungkin perlu beberapa saat untuk menghapus tabel, bergantung pada sumber daya yang digunakan (seperti data yang disimpan dalam tabel, dan setiap aliran atau indeks pada tabel).

Di akhir operasi `DeleteTable`, tabel tidak akan ada lagi di DynamoDB.

## Menggunakan perlindungan penghapusan
<a name="WorkingWithTables.Basics.DeletionProtection"></a>

Anda dapat melindungi tabel dari penghapusan yang tidak disengaja dengan properti perlindungan penghapusan. Mengaktifkan properti ini untuk tabel membantu memastikan bahwa tabel tersebut tidak terhapus secara tidak sengaja selama operasi manajemen tabel normal administrator. Hal ini juga membantu mencegah gangguan terhadap operasi bisnis normal.

 Pemilik tabel atau administrator yang berwenang mengontrol properti perlindungan penghapusan untuk setiap tabel. Properti perlindungan penghapusan untuk setiap tabel dinonaktifkan secara default. Ini termasuk replika global, dan tabel yang dipulihkan dari cadangan. Ketika perlindungan penghapusan dinonaktifkan untuk sebuah tabel, tabel tersebut dapat dihapus oleh pengguna mana pun yang diberi wewenang oleh kebijakan Manajemen Identitas dan Akses (IAM). Ketika perlindungan penghapusan diaktifkan untuk sebuah tabel, tabel tersebut tidak dapat dihapus oleh siapa pun. 

Untuk mengubah pengaturan ini, buka **Pengaturan tambahan** tabel, arahkan ke panel **Perlindungan Penghapusan** dan pilih **Aktifkan perlindungan penghapusan**. 

Properti proteksi penghapusan didukung oleh konsol DynamoDB, API, CLI/SDK dan. CloudFormation`CreateTable` API mendukung properti proteksi penghapusan pada waktu pembuatan tabel, dan `UpdateTable` API mendukung perubahan properti proteksi penghapusan untuk tabel yang ada.

**catatan**  
Jika AWS akun dihapus, semua data akun tersebut termasuk tabel masih dihapus dalam waktu 90 hari.
Jika DynamoDB kehilangan akses ke kunci yang dikelola pelanggan yang digunakan untuk mengenkripsi tabel, DynamoDB akan tetap mengarsipkan tabel tersebut. Pengarsipan melibatkan membuat cadangan tabel dan menghapus aslinya.

## Mencantumkan nama tabel
<a name="WorkingWithTables.Basics.ListTables"></a>

`ListTables`Operasi mengembalikan nama-nama tabel DynamoDB untuk akun AWS saat ini dan Wilayah.

**Example**  
 AWS CLI Contoh berikut menunjukkan bagaimana untuk daftar nama tabel DynamoDB.  

```
aws dynamodb list-tables
```

## Menggambarkan kuota throughput yang disediakan
<a name="WorkingWithTables.Basics.DescribeLimits"></a>

`DescribeLimits`Operasi mengembalikan kuota kapasitas baca dan tulis saat ini untuk AWS akun saat ini dan Wilayah.

**Example**  
 AWS CLI Contoh berikut menunjukkan bagaimana mendeskripsikan kuota throughput yang disediakan saat ini.  

```
aws dynamodb describe-limits
```
Output menunjukkan kuota atas unit kapasitas baca dan tulis untuk AWS akun saat ini dan Wilayah.

Untuk informasi selengkapnya tentang kuota ini, dan cara meminta peningkatan kuota, lihat [Kuota default throughput](ServiceQuotas.md#default-limits-throughput).

# Pertimbangan saat memilih kelas tabel di DynamoDB
<a name="WorkingWithTables.tableclasses"></a>

DynamoDB menawarkan dua kelas tabel yang dirancang untuk membantu Anda mengoptimalkan biaya. Kelas tabel Standar DynamoDB adalah defaultnya, dan direkomendasikan untuk sebagian besar beban kerja. Kelas tabel DynamoDB Standard-Infrequent Access (DynamoDB Standard-IA) dioptimalkan untuk tabel yang biayanya didominasi oleh penyimpanan. Misalnya, tabel yang menyimpan data yang jarang diakses, seperti log aplikasi, postingan media sosial lama, riwayat pesanan e-niaga, dan pencapaian game sebelumnya, merupakan kandidat yang baik untuk kelas tabel Standard-IA.

Setiap tabel DynamoDB dikaitkan dengan kelas tabel. Semua indeks sekunder yang terkait dengan tabel menggunakan kelas tabel yang sama. Anda dapat mengatur kelas tabel Anda saat membuat tabel Anda (DynamoDB Standard secara default) dan memperbarui kelas tabel tabel yang ada menggunakan Konsol Manajemen AWS, AWS CLI, atau SDK. AWS DynamoDB juga mendukung pengelolaan kelas tabel Anda AWS CloudFormation menggunakan tabel satu wilayah (tabel yang bukan tabel global). Setiap kelas tabel menawarkan harga yang berbeda untuk penyimpanan data serta permintaan baca dan tulis. Saat memilih kelas tabel untuk tabel Anda, ingatlah hal berikut:
+ Kelas tabel DynamoDB Standard menawarkan biaya throughput yang lebih rendah daripada DynamoDB Standard-IA dan merupakan opsi yang paling hemat biaya untuk tabel di mana throughput adalah biaya dominan. 
+ Kelas tabel DynamoDB Standard-IA menawarkan biaya penyimpanan yang lebih rendah dibandingkan DynamoDB Standard, dan merupakan pilihan paling hemat biaya untuk tabel di mana penyimpanan merupakan biaya dominan. Ketika penyimpanan melebihi 50% biaya throughput (baca dan tulis) tabel yang menggunakan kelas tabel Standar DynamoDB, kelas tabel IA-Standar DynamoDB dapat membantu Anda mengurangi total biaya tabel. 
+ Tabel DynamoDB Standard-IA menawarkan performa, ketahanan, dan ketersediaan yang sama dengan tabel DynamoDB Standard. 
+ Beralih antara kelas tabel DynamoDB Standard dan DynamoDB Standard-IA tidak memerlukan perubahan kode aplikasi Anda. Anda menggunakan APIs DynamoDB dan titik akhir layanan yang sama terlepas dari kelas tabel yang digunakan tabel Anda. 
+ Tabel DynamoDB Standard-IA kompatibel dengan semua fitur DynamoDB yang ada seperti auto scaling, on-demand mode, (TTL), on-demand backup, recovery (PITR) time-to-live, dan indeks sekunder global. point-in-time

Kelas tabel yang paling hemat biaya untuk tabel Anda bergantung pada penyimpanan yang diharapkan dan pola penggunaan throughput tabel Anda. Anda dapat melihat penyimpanan historis dan biaya throughput dan penggunaan tabel Anda dengan Laporan AWS Biaya dan Penggunaan dan AWS Cost Explorer. Gunakan data historis ini untuk menentukan kelas tabel yang paling hemat biaya untuk tabel Anda. Untuk mempelajari lebih lanjut tentang menggunakan Laporan AWS Biaya dan Penggunaan serta AWS Cost Explorer, lihat Dokumentasi [AWS Billing and Cost Management](https://docs.aws.amazon.com/account-billing/index.html). Lihat Harga [Amazon DynamoDB](https://aws.amazon.com/dynamodb/pricing/on-demand/) untuk detail tentang harga kelas tabel.

**catatan**  
Pembaruan kelas tabel adalah proses latar belakang. Anda masih dapat mengakses tabel Anda secara normal selama pembaruan kelas tabel. Waktu untuk memperbarui kelas tabel Anda bergantung pada lalu lintas tabel, ukuran penyimpanan, dan variabel terkait lainnya. Tidak lebih dari dua pembaruan kelas tabel di tabel Anda diperbolehkan dalam periode akhir 30 hari.

# Menambahkan tag dan label ke sumber daya di DynamoDB
<a name="Tagging"></a>

Anda dapat memberi label pada sumber daya Amazon DynamoDB menggunakan *tag*. Tanda memungkinkan Anda mengategorikan sumber daya dengan berbagai cara, misalnya berdasarkan tujuan, pemilik, lingkungan, atau kriteria lainnya. Tanda membantu Anda melakukan hal berikut:
+ Identifikasi sumber daya dengan cepat berdasarkan tanda yang Anda tetapkan padanya.
+ Lihat AWS tagihan yang dipecah berdasarkan tag.
**catatan**  
Setiap indeks sekunder lokal (LSI) dan indeks sekunder global (GSI) yang terkait dengan tabel yang diberi tanda akan diberi label dengan tanda yang sama secara otomatis. Saat ini, penggunaan DynamoDB Streams tidak dapat diberi tag.

Penandaan didukung oleh AWS layanan seperti Amazon EC2, Amazon S3, DynamoDB, dan banyak lagi. Penandaan yang efisien dapat memberikan wawasan biaya dengan memungkinkan Anda membuat laporan di seluruh layanan yang membawa tanda tertentu.

Untuk memulai penandaan, lakukan hal berikut:

1. Pahami [Pembatasan penandaan di DynamoDB](#TaggingRestrictions).

1. Buat tanda menggunakan [Penandaan pada sumber daya di DynamoDB](Tagging.Operations.md).

1. Gunakan [Menggunakan tag DynamoDB untuk membuat laporan alokasi biaya](#CostAllocationReports) untuk melacak AWS biaya Anda per tag aktif.

Terakhir, merupakan praktik yang baik untuk mengikuti strategi penandaan yang optimal. Untuk informasi selengkapnya, lihat [Strategi penandaan AWS](https://d0.awsstatic.com/aws-answers/AWS_Tagging_Strategies.pdf).

## Pembatasan penandaan di DynamoDB
<a name="TaggingRestrictions"></a>

 Setiap tanda terdiri dari kunci dan nilai, yang keduanya Anda tentukan. Pembatasan berikut berlaku: 
+  Setiap tabel DynamoDB hanya dapat memiliki satu tanda dengan kunci yang sama. Jika Anda mencoba menambahkan tanda yang ada (kunci yang sama), nilai tanda yang ada akan diperbarui ke nilai baru. 
+  Kunci dan nilai tanda peka huruf besar-kecil. 
+  Panjang kunci maksimum adalah 128 karakter Unicode. 
+ Panjang nilai maksimum adalah 256 karakter Unicode. 
+  Karakter yang diperbolehkan adalah huruf, spasi kosong, dan angka, ditambah karakter khusus berikut: `+ - = . _ : /` 
+  Jumlah maksimum tanda per sumber daya adalah 50.
+ Ukuran maksimum yang didukung untuk semua tag dalam tabel adalah 10 KB.
+ AWS-Assigned nama tag dan nilai secara otomatis diberi `aws:` awalan, yang tidak dapat Anda tetapkan. AWS-nama tag yang ditetapkan tidak dihitung terhadap batas tag 50 atau batas ukuran maksimum 10 KB. Nama tanda yang ditetapkan pengguna memiliki prefiks `user:` dalam laporan alokasi biaya. 
+  Anda tidak dapat mengubah penerapan tanda ke versi sebelumnya. 

# Penandaan pada sumber daya di DynamoDB
<a name="Tagging.Operations"></a>

Anda dapat menggunakan konsol Amazon DynamoDB atau AWS Command Line Interface AWS CLI() untuk menambahkan, membuat daftar, mengedit, atau menghapus tag. Anda kemudian dapat mengaktifkan tanda yang ditetapkan pengguna ini sehingga mereka muncul di konsol AWS Manajemen Penagihan dan Biaya untuk pelacakan alokasi biaya. Untuk informasi selengkapnya, lihat [Menggunakan tag DynamoDB untuk membuat laporan alokasi biaya](Tagging.md#CostAllocationReports). 

 Untuk pengeditan massal, Anda juga dapat menggunakan Editor Tanda di Konsol Manajemen AWS. Untuk informasi selengkapnya, silakan lihat [Bekerja dengan Editor Tag](https://docs.aws.amazon.com/awsconsolehelpdocs/latest/gsg/tag-editor.html).

 Untuk menggunakan DynamoDB API, lihat operasi berikut di [Referensi API Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/):
+ [TagResource](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TagResource.html)
+ [UntagResource](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UntagResource.html)
+ [ListTagsOfResource](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ListTagsOfResource.html)

**Topics**
+ [Menetapkan izin untuk memfilter menurut tag](#Tagging.Operations.permissions)
+ [Menambahkan tanda ke tabel baru atau yang sudah ada (Konsol Manajemen AWS)](#Tagging.Operations.using-console)
+ [Menambahkan tanda ke tabel baru atau yang sudah ada (AWS CLI)](#Tagging.Operations.using-cli)

## Menetapkan izin untuk memfilter menurut tag
<a name="Tagging.Operations.permissions"></a>

Untuk menggunakan tanda guna memfilter daftar tabel Anda di konsol DynamoDB, pastikan kebijakan pengguna Anda mencakup akses ke operasi berikut:
+ `tag:GetTagKeys`
+ `tag:GetTagValues`

Anda dapat mengakses operasi ini dengan melampirkan kebijakan IAM baru untuk pengguna Anda dengan mengikuti langkah-langkah di bawah ini.

1. Buka [konsol IAM](https://console.aws.amazon.com/iam/) dengan pengguna Admin.

1. Pilih "Kebijakan" di menu navigasi kiri.

1. Pilih "Buat kebijakan".

1. Tempelkan kebijakan berikut ke editor JSON.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "tag:GetTagKeys",
                   "tag:GetTagValues"
               ],
               "Resource": "*"
           }
       ]
   }
   ```

------

1. Selesaikan panduan dan tetapkan nama untuk kebijakan (misalnya, `TagKeysAndValuesReadAccess`).

1. Pilih "Pengguna" di menu navigasi kiri.

1. Dari daftar, pilih pengguna yang biasanya Anda gunakan untuk mengakses konsol DynamoDB.

1. Pilih "Tambahkan izin".

1. Pilih "Lampirkan kebijakan yang ada secara langsung".

1. Dari daftar, pilih kebijakan yang Anda buat sebelumnya.

1. Selesaikan panduan.

## Menambahkan tanda ke tabel baru atau yang sudah ada (Konsol Manajemen AWS)
<a name="Tagging.Operations.using-console"></a>

Anda dapat menggunakan konsol DynamoDB untuk menambahkan tanda ke tabel baru saat Anda membuatnya, atau untuk menambahkan, mengedit, atau menghapus tanda untuk tabel yang ada.

**Untuk memberi tanda pada sumber daya saat pembuatan (konsol)**

1. Masuk ke Konsol Manajemen AWS dan buka konsol DynamoDB di. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Di panel navigasi, pilih **Tabel**, lalu pilih **Buat tabel**.

1. Pada halaman **Buat tabel DynamoDB**, masukkan nama dan kunci primer. Di bagian **Tanda**, pilih **Tambahkan tanda baru** dan masukkan tanda yang ingin Anda gunakan.

   Untuk informasi selengkapnya tentang struktur tag, lihat [Pembatasan penandaan di DynamoDB](Tagging.md#TaggingRestrictions). 

   Untuk informasi selengkapnya tentang membuat tabel, lihat [Operasi dasar pada tabel DynamoDB](WorkingWithTables.Basics.md).

**Untuk memberi tanda pada sumber daya yang ada (konsol)**

Buka konsol DynamoDB di. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Di panel navigasi, pilih **Tabel**.

1. Pilih tabel dalam daftar, lalu pilih tab **Pengaturan tambahan**. Anda dapat menambahkan, mengedit, atau menghapus **tanda** di bagian bawah halaman.

## Menambahkan tanda ke tabel baru atau yang sudah ada (AWS CLI)
<a name="Tagging.Operations.using-cli"></a>

Contoh berikut menunjukkan cara menggunakan tag AWS CLI untuk menentukan saat Anda membuat tabel dan indeks, dan untuk menandai sumber daya yang ada.

**Untuk memberi tanda pada sumber daya saat pembuatan (AWS CLI)**
+ Contoh berikut membuat tabel `Movies` baru dan menambahkan tanda `Owner` dengan nilai `blueTeam`: 

  ```
  aws dynamodb create-table \
      --table-name Movies \
      --attribute-definitions AttributeName=Title,AttributeType=S \
      --key-schema AttributeName=Title,KeyType=HASH \
      --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
      --tags Key=Owner,Value=blueTeam
  ```

**Untuk memberi tanda pada sumber daya yang ada (AWS CLI)**
+ Contoh berikut menambahkan tanda `Owner` dengan nilai `blueTeam` untuk tabel `Movies`: 

  ```
  aws dynamodb tag-resource \
      --resource-arn arn:aws:dynamodb:us-east-1:123456789012:table/Movies \
      --tags Key=Owner,Value=blueTeam
  ```

**Untuk mencantumkan semua tanda untuk tabel (AWS CLI)**
+ Contoh berikut mencantumkan semua tanda yang terkait dengan tabel `Movies`:

  ```
  aws dynamodb list-tags-of-resource \
      --resource-arn arn:aws:dynamodb:us-east-1:123456789012:table/Movies
  ```

## Menggunakan tag DynamoDB untuk membuat laporan alokasi biaya
<a name="CostAllocationReports"></a>

AWS menggunakan tag untuk mengatur biaya sumber daya pada laporan alokasi biaya Anda. AWS menyediakan dua jenis tag alokasi biaya:
+ Tag AWS yang dihasilkan. AWS mendefinisikan, membuat, dan menerapkan tag ini untuk Anda.
+ Tanda yang ditentukan pengguna. Anda menentukan, membuat, dan menerapkan tanda ini.

Anda harus mengaktifkan kedua jenis tanda secara terpisah sebelum tanda tersebut muncul di Cost Explorer atau laporan alokasi biaya. 

 Untuk mengaktifkan tag AWS yang dihasilkan: 

1.  Masuk ke Konsol Manajemen AWS dan buka konsol Billing and Cost Management [https://console.aws.amazon.com/billing/di](https://console.aws.amazon.com/billing/home#/.) rumah\$1/. 

1.  Di panel navigasi, pilih **Tanda Alokasi Biaya**. 

1.  Di bagian **Tanda Alokasi Biaya yang Dihasilkan AWS**, pilih **Aktifkan**. 

 Untuk mengaktifkan tanda yang ditentukan pengguna: 

1.  Masuk ke Konsol Manajemen AWS dan buka konsol Billing and Cost Management [https://console.aws.amazon.com/billing/di](https://console.aws.amazon.com/billing/home#/.) rumah\$1/. 

1.  Di panel navigasi, pilih **Tanda Alokasi Biaya**. 

1.  Di bagian **Tanda Alokasi Biaya yang Ditentukan Pengguna**, pilih **Aktifkan**. 

 Setelah Anda membuat dan mengaktifkan tag, AWS buat laporan alokasi biaya dengan penggunaan dan biaya yang dikelompokkan berdasarkan tag aktif Anda. Laporan alokasi biaya mencakup semua AWS biaya Anda untuk setiap periode penagihan. Laporan ini mencakup sumber daya yang diberi tanda dan tidak diberi tanda, sehingga Anda dapat mengatur biaya untuk sumber daya dengan jelas. 

**catatan**  
 Saat ini, data apa pun yang ditransfer dari DynamoDB tidak akan diperinci menurut tanda pada laporan alokasi biaya. 

 Untuk informasi selengkapnya, lihat [Menggunakan tanda alokasi biaya](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html). 

# Tabel global - multi-aktif, replikasi Multi-wilayah
<a name="GlobalTables"></a>

Tabel *global Amazon DynamoDB* adalah fitur database multi-aktif yang dikelola sepenuhnya, Multi-wilayah, dan multi-aktif yang menyediakan replikasi data yang mudah digunakan serta kinerja baca dan tulis lokal yang cepat untuk aplikasi berskala global.

Tabel global secara otomatis mereplikasi data tabel DynamoDB Anda Wilayah AWS di seluruh dan secara opsional di AWS seluruh akun tanpa mengharuskan Anda membuat dan memelihara solusi replikasi Anda sendiri. Tabel global ideal untuk aplikasi yang membutuhkan kelangsungan bisnis dan ketersediaan tinggi melalui penyebaran Multi-wilayah. Setiap replika tabel global dapat melayani membaca dan menulis. Aplikasi dapat mencapai ketahanan tinggi dengan Recovery Point Objective (RPO) rendah atau nol dengan mengalihkan lalu lintas ke Wilayah lain jika pemrosesan aplikasi terganggu di suatu Wilayah. Tabel global tersedia di semua Wilayah di mana DynamoDB tersedia.

## Mode konsistensi
<a name="GlobalTables.consistency-modes"></a>

Saat Anda membuat tabel global, Anda dapat mengonfigurasi mode konsistensinya. Tabel global mendukung dua mode konsistensi: Multi-region end consistency (MREC) dan Multi-region strong consistency (MRSC).

Jika Anda tidak menentukan mode konsistensi saat membuat tabel global, tabel global default ke Multi-region end consistency (MREC). Tabel global tidak dapat berisi replika yang dikonfigurasi dengan mode konsistensi yang berbeda. Anda tidak dapat mengubah mode konsistensi tabel global setelah pembuatan.

## Konfigurasi akun
<a name="GlobalTables.account-configurations"></a>

DynamoDB sekarang mendukung dua model tabel global, masing-masing dirancang untuk pola arsitektur yang berbeda:
+ **Tabel global akun yang sama** - Semua replika dibuat dan dikelola dalam satu akun. AWS 
+ **Tabel global multi-akun** — Replika digunakan di beberapa AWS akun saat berpartisipasi dalam grup replikasi bersama.

Model akun yang sama dan multi-akun mendukung penulisan Multi-wilayah, replikasi asinkron, resolusi last-writer-wins konflik, dan model penagihan yang sama. Namun, mereka berbeda dalam cara akun, izin, enkripsi, dan tata kelola tabel dikelola.

Tabel global yang dikonfigurasi untuk MRSC hanya mendukung konfigurasi akun yang sama.

Anda dapat mengonfigurasi tabel global menggunakan AWS Management Console. Tabel global menggunakan APIs DynamoDB yang ada untuk membaca dan menulis data ke tabel Anda, sehingga tidak diperlukan perubahan aplikasi. Anda hanya membayar untuk sumber daya yang Anda sediakan atau gunakan, tanpa biaya atau komitmen di muka.


| **Sifat-sifat** | **Tabel global Akun Sama** | **Tabel global multi-akun** | 
| --- | --- | --- | 
| Kasus penggunaan primer | Ketahanan Multi-Wilayah untuk aplikasi dalam satu akun AWS  | Multi-Region, replikasi multi-akun untuk aplikasi yang dimiliki oleh tim yang berbeda, unit bisnis yang berbeda, atau batas keamanan yang kuat di seluruh akun | 
| Model akun | Semua replika dibuat dan dikelola dalam satu akun AWS  | Replika dibuat di beberapa AWS akun dalam penerapan yang sama | 
| Kepemilikan sumber daya | Satu akun memiliki tabel dan semua replika | Setiap akun memiliki replika lokalnya; grup replikasi mencakup akun | 
| Versi yang didukung | Tabel global versi 2019.11.21 (Saat Ini) dan Versi 2017.11.29 (Legacy) | Versi tabel global 2019.11.21 (Saat ini) | 
| Kontrol operasi pesawat | Membuat, memodifikasi, dan menghapus replika melalui akun pemilik tabel | Operasi bidang kontrol terdistribusi: akun bergabung atau keluar dari grup replikasi | 
| Operasi pesawat data | Titik akhir DynamoDB standar per Wilayah | Akses data-plane per akun/wilayah; routing melalui grup replikasi | 
| Batas keamanan | Batas IAM dan KMS tunggal | IAM, KMS, penagihan, dan tata kelola yang berbeda CloudTrail per akun | 
| Paling cocok | Organizations dengan kepemilikan tabel terpusat | Organizations dengan tim federasi, batas tata kelola, atau pengaturan multi-akun | 

**Topics**
+ [Mode konsistensi](#GlobalTables.consistency-modes)
+ [Konfigurasi akun](#GlobalTables.account-configurations)
+ [Konsep inti tabel global](globaltables-CoreConcepts.md)
+ [DynamoDB tabel global akun yang sama](globaltables-SameAccount.md)
+ [Tabel global multi-akun DynamoDB](globaltables-MultiAccount.md)
+ [Memahami penagihan Amazon DynamoDB untuk tabel global](global-tables-billing.md)
+ [DynamoDB versi tabel global](V2globaltables_versions.md)
+ [Praktik terbaik untuk tabel global](globaltables-bestpractices.md)

# Konsep inti tabel global
<a name="globaltables-CoreConcepts"></a>

Bagian berikut menjelaskan konsep dan perilaku tabel global di Amazon DynamoDB

## Konsep
<a name="globaltables-CoreConcepts.KeyConcepts"></a>

*Tabel global* adalah fitur DynamoDB yang mereplikasi data tabel di seluruh Wilayah. AWS 

*Tabel replika* (atau replika) adalah tabel DynamoDB yang berfungsi sebagai bagian dari tabel global. Tabel global terdiri dari dua atau lebih tabel replika di berbagai AWS Wilayah. Setiap tabel global hanya dapat memiliki satu replika per AWS Wilayah. Semua replika dalam tabel global berbagi nama tabel, skema kunci primer, dan data item yang sama.

Saat aplikasi menulis data ke replika di satu Wilayah, DynamoDB secara otomatis mereplikasi penulisan ke semua replika lain dalam tabel global. Untuk informasi selengkapnya tentang cara memulai dengan tabel global, lihat [Tutorial: Membuat tabel global](V2globaltables.tutorial.md) atau[Tutorial: Membuat tabel global multi-akun](V2globaltables_MA.tutorial.md).

## Versi
<a name="globaltables-CoreConcepts.Versions"></a>

Ada dua versi tabel global DynamoDB yang tersedia[: Tabel Global versi 2019.11.21 (Saat](GlobalTables.md) Ini) dan. [Versi tabel global 2017.11.29 (Legacy)](globaltables.V1.md) Anda harus menggunakan Tabel Global versi 2019.11.21 (Saat ini) bila memungkinkan. Informasi di bagian dokumentasi ini adalah untuk Versi 2019.11.21 (Saat ini). Untuk informasi selengkapnya, lihat Menentukan versi tabel global[Menentukan versi tabel global](V2globaltables_versions.md#globaltables.DetermineVersion).

## Ketersediaan
<a name="globaltables-CoreConcepts.availability"></a>

Tabel global membantu meningkatkan kelangsungan bisnis Anda dengan membuatnya lebih mudah untuk menerapkan arsitektur ketersediaan tinggi Multi-wilayah. Jika beban kerja di satu AWS Wilayah menjadi terganggu, Anda dapat mengalihkan lalu lintas aplikasi ke Wilayah yang berbeda dan melakukan pembacaan dan penulisan ke tabel replika yang berbeda dalam tabel global yang sama.

Setiap tabel replika dalam tabel global memberikan daya tahan dan ketersediaan yang sama dengan tabel DynamoDB wilayah Tunggal. Tabel global menawarkan 99,999% ketersediaan [Service Level Agreement (SLA)](https://aws.amazon.com//dynamodb/sla/), dibandingkan dengan 99,99% untuk tabel Single-region.

## Pengujian injeksi kesalahan
<a name="fault-injection-testing"></a>

Baik tabel global MREC dan MRSC terintegrasi dengan [AWSAWS Fault Injection Service](https://docs.aws.amazon.com/resilience-hub/latest/userguide/testing.html) (FIS), layanan yang dikelola sepenuhnya untuk menjalankan eksperimen injeksi kesalahan terkontrol untuk meningkatkan ketahanan aplikasi. Menggunakan AWS FIS, Anda dapat:
+ Buat templat eksperimen yang menentukan skenario kegagalan tertentu.
+ Menyuntikkan kegagalan untuk memvalidasi ketahanan aplikasi dengan mensimulasikan isolasi Wilayah (yaitu, menjeda replikasi ke dan dari replika yang dipilih) untuk menguji penanganan kesalahan, mekanisme pemulihan, dan perilaku pergeseran lalu lintas multi-wilayah ketika satu Wilayah mengalami gangguan. AWS 

Misalnya, dalam tabel global dengan replika di AS Timur (Virginia N.), AS Timur (Ohio), dan AS Barat (Oregon), Anda dapat menjalankan eksperimen di AS Timur (Ohio) untuk menguji isolasi wilayah di sana sementara AS Timur (Virginia N.) dan AS Barat (Oregon) melanjutkan operasi normal. Pengujian terkontrol ini membantu Anda mengidentifikasi dan menyelesaikan masalah potensial sebelum memengaruhi beban kerja produksi. 

Lihat [Target tindakan](https://docs.aws.amazon.com/fis/latest/userguide/action-sequence.html#action-targets) dalam *panduan pengguna AWS FIS* untuk daftar lengkap tindakan yang didukung AWS FIS dan [Konektivitas Lintas Wilayah](https://docs.aws.amazon.com/fis/latest/userguide/cross-region-scenario.html) untuk menjeda replikasi DynamoDB antar wilayah.

*Untuk informasi tentang tindakan tabel global Amazon DynamoDB yang tersedia AWS di FIS, [lihat referensi tindakan tabel global DynamoDB di Panduan Pengguna FIS](https://docs.aws.amazon.com/fis/latest/userguide/fis-actions-reference.html#dynamodb-actions-reference).AWS *

Untuk mulai menjalankan eksperimen injeksi kesalahan, lihat [Merencanakan eksperimen AWS FIS Anda](https://docs.aws.amazon.com/fis/latest/userguide/getting-started-planning.html) di panduan pengguna AWS FIS.

**catatan**  
Selama AWS FIS percobaan di MRSC, pembacaan yang konsisten pada akhirnya diizinkan, tetapi pembaruan pengaturan tabel - seperti mengubah mode penagihan atau mengonfigurasi throughput tabel - tidak diizinkan, mirip dengan MREC. Silakan periksa CloudWatch metrik [`FaultInjectionServiceInducedErrors`](metrics-dimensions.md#FaultInjectionServiceInducedErrors)untuk detail tambahan mengenai kode kesalahan.

## Waktu Untuk Tayang (TTL)
<a name="global-tables-ttl"></a>

Tabel global yang dikonfigurasi untuk dukungan MREC mengonfigurasi penghapusan [Time To Live](TTL.md) (TTL). Pengaturan TTL secara otomatis disinkronkan untuk semua replika dalam tabel global. Ketika TTL menghapus item dari replika di Wilayah, penghapusan direplikasi ke semua replika lain di tabel global. TTL tidak menggunakan kapasitas tulis, jadi Anda tidak dikenakan biaya untuk penghapusan TTL di Wilayah tempat penghapusan terjadi. Namun, Anda dikenakan biaya untuk penghapusan yang direplikasi di setiap wilayah lain dengan replika di tabel global.

Replikasi penghapusan TTL mengkonsumsi kapasitas tulis pada replika tempat penghapusan direplikasi. Replika yang dikonfigurasi untuk kapasitas yang disediakan dapat membatasi permintaan jika kombinasi throughput tulis dan throughput penghapusan TTL lebih tinggi daripada kapasitas tulis yang disediakan.

Tabel global yang dikonfigurasi untuk konsistensi kuat Multi-wilayah (MRSC) tidak mendukung konfigurasi penghapusan Time To Live (TTL).

## Pengaliran
<a name="global-tables-streams"></a>

Tabel global yang dikonfigurasi untuk konsistensi akhir Multi-wilayah (MREC) mereplikasi perubahan dengan membaca perubahan tersebut dari [DynamoDB Stream](Streams.md) pada tabel replika dan menerapkan perubahan itu ke semua tabel replika lainnya. Oleh karena itu, aliran diaktifkan secara default pada semua replika dalam tabel global MREC, dan tidak dapat dinonaktifkan pada replika tersebut. Proses replikasi MREC dapat menggabungkan beberapa perubahan dalam waktu singkat menjadi satu penulisan yang direplikasi, sehingga setiap Stream replika berisi catatan yang sedikit berbeda. Streaming rekaman pada replika MREC mempertahankan urutan untuk semua perubahan pada item yang sama, tetapi urutan relatif perubahan pada item yang berbeda dapat bervariasi di seluruh replika.

Jika Anda ingin menulis aplikasi yang memproses catatan Streams untuk perubahan yang terjadi di Wilayah tertentu tetapi tidak Wilayah lain dalam tabel global, Anda dapat menambahkan atribut ke setiap item yang menentukan di Wilayah mana perubahan untuk item tersebut terjadi. Anda dapat menggunakan atribut ini untuk memfilter catatan Streams untuk perubahan yang terjadi di Wilayah lain, termasuk penggunaan filter peristiwa Lambda untuk hanya memanggil fungsi Lambda untuk perubahan di Wilayah tertentu.

Tabel global yang dikonfigurasi untuk Multi-region strong consistency (MRSC) tidak menggunakan DynamoDB Streams untuk replikasi, sehingga Streams tidak diaktifkan secara default pada replika MRSC. Anda dapat mengaktifkan Streams pada replika MRSC. Catatan aliran pada replika MRSC identik untuk setiap replika, termasuk urutan rekaman Stream.

## Transaksi
<a name="global-tables-transactions"></a>

Pada tabel global yang dikonfigurasi untuk MREC, operasi transaksi DynamoDB ([https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html)dan [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html)) hanya atom dalam Wilayah tempat operasi dipanggil. Penulisan transaksional tidak direplikasi sebagai unit di seluruh Wilayah, yang berarti hanya beberapa penulisan dalam transaksi yang dapat dikembalikan oleh operasi baca di replika lain pada titik waktu tertentu.

Misalnya, jika Anda memiliki tabel global dengan replika di Wilayah AS Timur (Ohio) dan AS Barat (Oregon) dan melakukan `TransactWriteItems` operasi di Wilayah AS Timur (Ohio), Anda dapat mengamati transaksi yang diselesaikan sebagian di Wilayah Barat AS (Oregon) saat perubahan direplikasi. Perubahan hanya akan direplikasi ke Wilayah lain setelah dilakukan di Wilayah sumber.

Tabel global yang dikonfigurasi untuk konsistensi kuat Multi-wilayah (MRSC) tidak mendukung operasi transaksi, dan akan mengembalikan kesalahan jika operasi tersebut dipanggil pada replika MRSC.

## Throughput baca dan tulis
<a name="globaltables-CoreConcepts.Throughput"></a>

### Mode yang disediakan
<a name="gt_throughput.provisioned"></a>

Replikasi mengkonsumsi kapasitas tulis. Replika yang dikonfigurasi untuk kapasitas yang disediakan dapat membatasi permintaan jika kombinasi throughput penulisan aplikasi dan throughput penulisan replikasi melebihi kapasitas penulisan yang disediakan. Untuk tabel global yang menggunakan mode yang disediakan, pengaturan penskalaan otomatis untuk kapasitas baca dan tulis disinkronkan antar replika.

Anda dapat secara independen mengonfigurasi pengaturan kapasitas baca untuk setiap replika dalam tabel global dengan menggunakan [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ProvisionedThroughputOverride.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ProvisionedThroughputOverride.html)parameter di tingkat replika. Secara default, perubahan kapasitas baca yang disediakan diterapkan ke semua replika dalam tabel global. Saat menambahkan replika baru ke tabel global, kapasitas baca tabel sumber atau replika digunakan sebagai nilai awal kecuali penggantian tingkat replika ditentukan secara eksplisit.

### Mode sesuai permintaan
<a name="gt_throughput.on-demand"></a>

Untuk tabel global yang dikonfigurasi untuk mode sesuai permintaan, kapasitas tulis secara otomatis disinkronkan di semua replika. DynamoDB secara otomatis menyesuaikan kapasitas berdasarkan lalu lintas, dan tidak ada pengaturan kapasitas baca atau tulis khusus replika untuk dikelola.

## Memantau tabel global
<a name="monitoring-global-tables"></a>

Tabel global yang dikonfigurasi untuk konsistensi akhir Multi-wilayah (MREC) mempublikasikan metrik ke. [`ReplicationLatency`](metrics-dimensions.md#ReplicationLatency) CloudWatch Metrik ini melacak waktu yang telah berlalu antara saat item ditulis ke tabel replika, dan kapan item itu muncul di replika lain di tabel global. `ReplicationLatency`dinyatakan dalam milidetik dan dipancarkan untuk setiap pasangan Wilayah sumber dan tujuan dalam tabel global. 

`ReplicationLatency`Nilai tipikal tergantung pada jarak antara AWS Wilayah yang Anda pilih, serta variabel lain seperti jenis beban kerja dan throughput. Misalnya, replika sumber di Wilayah AS Barat (California Utara) (us-west-1) memiliki lebih rendah `ReplicationLatency` ke Wilayah Barat AS (Oregon) (us-west-2) dibandingkan dengan Wilayah Afrika (Cape Town) (af-south-1).

Nilai yang meningkat untuk `ReplicationLatency` dapat menunjukkan bahwa pembaruan dari satu replika tidak menyebar ke tabel replika lain secara tepat waktu. Dalam hal ini, Anda dapat mengalihkan sementara aktivitas baca dan tulis aplikasi Anda ke AWS Wilayah yang berbeda.

Tabel global yang dikonfigurasi untuk konsistensi kuat Multi-wilayah (MRSC) tidak mempublikasikan metrik. `ReplicationLatency`

## Pertimbangan untuk mengelola tabel global
<a name="management-considerations"></a>

Anda tidak dapat menghapus tabel yang digunakan untuk menambahkan replika tabel global baru hingga 24 jam berlalu sejak replika baru dibuat.

Jika Anda menonaktifkan AWS Wilayah yang berisi replika tabel global, replika tersebut akan dikonversi secara permanen ke tabel Wilayah tunggal 20 jam setelah Wilayah dinonaktifkan.

# DynamoDB tabel global akun yang sama
<a name="globaltables-SameAccount"></a>

Tabel global akun yang sama secara otomatis mereplikasi data tabel DynamoDB Anda di seluruh Wilayah dalam satu akun. AWS AWS Tabel global akun yang sama menyediakan model paling sederhana untuk menjalankan aplikasi Multi-wilayah karena semua replika memiliki batas akun, kepemilikan, dan model izin yang sama. Saat Anda memilih AWS Wilayah untuk tabel replika Anda, tabel global menangani semua replikasi secara otomatis. Tabel global tersedia di semua Wilayah di mana DynamoDB tersedia.

Tabel global akun yang sama memberikan manfaat berikut:
+ Replikasi data tabel DynamoDB secara otomatis di seluruh Wilayah pilihan Anda untuk menemukan data AWS yang lebih dekat dengan pengguna Anda
+ Aktifkan ketersediaan aplikasi yang lebih tinggi selama isolasi atau degradasi regional
+ Gunakan resolusi konflik bawaan sehingga Anda dapat fokus pada logika bisnis aplikasi Anda
+ Saat membuat tabel global akun yang sama, Anda dapat memilih salah satu atau [Konsistensi akhir Multi-Region (MREC)](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes.mrec) [Konsistensi kuat Multi-Region (MRSC)](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes.mrsc)

**Topics**
+ [Cara kerja tabel global DynamoDB](V2globaltables_HowItWorks.md)
+ [Tutorial: Membuat tabel global](V2globaltables.tutorial.md)
+ [DynamoDB tabel global keamanan](globaltables-security.md)

# Cara kerja tabel global DynamoDB
<a name="V2globaltables_HowItWorks"></a>

Bagian berikut menjelaskan konsep dan perilaku tabel global di Amazon DynamoDB.

## Konsep
<a name="V2globaltables_HowItWorks.KeyConcepts"></a>

*Tabel global* adalah fitur DynamoDB yang mereplikasi data tabel di seluruh Wilayah. AWS 

*Tabel replika* (atau replika) adalah tabel DynamoDB yang berfungsi sebagai bagian dari tabel global. Tabel global terdiri dari dua atau lebih tabel replika di berbagai AWS Wilayah. Setiap tabel global hanya dapat memiliki satu replika per AWS Wilayah. Semua replika dalam tabel global berbagi nama tabel, skema kunci primer, dan data item yang sama.

Saat aplikasi menulis data ke replika di satu Wilayah, DynamoDB secara otomatis mereplikasi penulisan ke semua replika lain dalam tabel global. Untuk informasi selengkapnya tentang cara mulai menggunakan tabel global, lihat [Tutorial: Membuat tabel global](V2globaltables.tutorial.md).

## Versi
<a name="V2globaltables_HowItWorks.versions"></a>

[Ada dua versi tabel global DynamoDB yang tersedia: Versi 2019.11.21 (Saat Ini) dan Versi 2017.11.29 (Legacy).](globaltables.V1.md) Anda harus menggunakan Versi 2019.11.21 (Saat ini) bila memungkinkan. Informasi di bagian dokumentasi ini adalah untuk Versi 2019.11.21 (Saat ini). Untuk informasi selengkapnya, lihat [Menentukan versi tabel global](V2globaltables_versions.md#globaltables.DetermineVersion).

## Ketersediaan
<a name="V2globaltables_HowItWorks.availability"></a>

Tabel global membantu meningkatkan kelangsungan bisnis Anda dengan membuatnya lebih mudah untuk menerapkan arsitektur ketersediaan tinggi Multi-wilayah. Jika beban kerja di satu AWS Wilayah menjadi terganggu, Anda dapat mengalihkan lalu lintas aplikasi ke Wilayah yang berbeda dan melakukan pembacaan dan penulisan ke tabel replika yang berbeda dalam tabel global yang sama.

Setiap tabel replika dalam tabel global memberikan daya tahan dan ketersediaan yang sama dengan tabel DynamoDB wilayah Tunggal. Tabel global menawarkan 99,999% ketersediaan [Service Level Agreement (SLA)](https://aws.amazon.com//dynamodb/sla/), dibandingkan dengan 99,99% untuk tabel Single-region.

## Mode konsistensi
<a name="V2globaltables_HowItWorks.consistency-modes"></a>

Saat Anda membuat tabel global, Anda dapat mengonfigurasi mode konsistensinya. Tabel global mendukung dua mode konsistensi: Multi-region end consistency (MREC), dan Multi-region strong consistency (MRSC).

Jika Anda tidak menentukan mode konsistensi saat membuat tabel global, tabel global default ke Multi-region end consistency (MREC). Tabel global tidak dapat berisi replika yang dikonfigurasi dengan mode konsistensi yang berbeda. Anda tidak dapat mengubah mode konsistensi tabel global setelah pembuatan.

### Konsistensi akhir Multi-Region (MREC)
<a name="V2globaltables_HowItWorks.consistency-modes.mrec"></a>

Konsistensi akhir Multi-Region (MREC) adalah mode konsistensi default untuk tabel global. Perubahan item dalam replika tabel global MREC direplikasi secara asinkron ke semua replika lainnya, biasanya dalam satu detik atau kurang. Jika replika dalam tabel global MREC menjadi terisolasi atau terganggu, data apa pun yang belum direplikasi ke Wilayah lain akan direplikasi ketika replika menjadi sehat.

Jika item yang sama dimodifikasi di beberapa Wilayah secara bersamaan, DynamoDB akan menyelesaikan konflik dengan menggunakan modifikasi dengan stempel waktu internal terbaru berdasarkan per item, yang disebut sebagai metode resolusi konflik “penulis terakhir menang”. Item pada akhirnya akan bertemu di semua replika ke versi yang dibuat oleh penulisan terakhir.

[Operasi pembacaan yang sangat konsisten](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html#DDB-GetItem-request-ConsistentRead) mengembalikan versi terbaru item jika item tersebut terakhir diperbarui di Wilayah tempat pembacaan terjadi, tetapi dapat mengembalikan data basi jika item terakhir diperbarui di Wilayah lain. Penulisan bersyarat mengevaluasi ekspresi kondisi terhadap versi item di Wilayah.

Anda membuat tabel global MREC dengan menambahkan replika ke tabel DynamoDB yang ada. Menambahkan replika tidak berdampak kinerja pada tabel DynamoDB wilayah Tunggal atau replika tabel global yang ada. Anda dapat menambahkan replika ke tabel global MREC untuk memperluas jumlah Wilayah tempat data direplikasi, atau menghapus replika dari tabel global MREC jika tidak diperlukan lagi. [Tabel global MREC dapat memiliki replika di Wilayah mana pun di mana DynamoDB tersedia, dan dapat memiliki replika sebanyak yang ada Wilayah di partisi.AWS](https://docs.aws.amazon.com/whitepapers/latest/aws-fault-isolation-boundaries/partitions.html)

### Konsistensi kuat Multi-Region (MRSC)
<a name="V2globaltables_HowItWorks.consistency-modes.mrsc"></a>

Anda dapat mengonfigurasi mode Multi-region strong consistency (MRSC) saat Anda membuat tabel global. Perubahan item dalam replika tabel global MRSC direplikasi secara sinkron ke setidaknya satu Wilayah lain sebelum operasi penulisan mengembalikan respons yang berhasil. Operasi baca yang sangat konsisten pada replika MRSC apa pun selalu mengembalikan versi terbaru dari suatu item. Penulisan bersyarat selalu mengevaluasi ekspresi kondisi terhadap versi terbaru dari suatu item.

Tabel global MRSC harus ditempatkan tepat di tiga Wilayah. Anda dapat mengonfigurasi tabel global MRSC dengan tiga replika, atau dengan dua replika dan satu saksi. Saksi adalah komponen dari tabel global MRSC yang berisi data yang ditulis ke replika tabel global dan memberikan alternatif opsional untuk replika lengkap sambil mendukung arsitektur ketersediaan MRSC. Anda tidak dapat melakukan operasi membaca atau menulis pada saksi. Seorang saksi berada di Wilayah yang berbeda dari dua replika. Saat membuat tabel global MRSC, Anda memilih Wilayah untuk replika dan penyebaran saksi pada waktu pembuatan tabel MRSC. Anda dapat menentukan apakah dan di Wilayah mana tabel global MRSC memiliki saksi yang dikonfigurasi dari output [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html)API. Saksi dimiliki dan dikelola oleh DynamoDB, dan saksi tidak akan muncul di akun AWS Anda di Wilayah tempat ia dikonfigurasi.

Tabel global MRSC tersedia dalam set Wilayah berikut: Set Wilayah AS (US East N. Virginia, US East Ohio, US West Oregon), set Wilayah UE (Eropa Irlandia, Eropa London, Eropa Paris, Eropa Frankfurt), dan set Wilayah AP (Asia Pasifik Tokyo, Asia Pasifik Seoul, dan Asia Pasifik Osaka). Tabel global MRSC tidak dapat menjangkau set Wilayah (misalnya tabel global MRSC tidak dapat berisi replika dari set Wilayah AS dan UE).

Anda membuat tabel global MRSC dengan menambahkan satu replika dan saksi atau dua replika ke tabel DynamoDB yang ada yang tidak berisi data. Saat mengonversi tabel Single-region yang ada ke tabel global MRSC, Anda harus memastikan bahwa tabel tersebut kosong. Mengonversi tabel wilayah Tunggal ke tabel global MRSC dengan item yang ada tidak didukung. Pastikan tidak ada data yang ditulis ke dalam tabel selama proses konversi. Anda tidak dapat menambahkan replika tambahan ke tabel global MRSC yang ada. Anda tidak dapat menghapus satu replika atau saksi dari tabel global MRSC. Anda dapat menghapus dua replika atau menghapus satu replika dan saksi dari tabel global MRSC, mengubah replika yang tersisa menjadi tabel DynamoDB wilayah tunggal.

Operasi tulis gagal dengan `ReplicatedWriteConflictException` ketika mencoba memodifikasi item yang sudah dimodifikasi di Wilayah lain. Menulis yang gagal dengan `ReplicatedWriteConflictException` dapat dicoba lagi dan akan berhasil jika item tidak lagi dimodifikasi di Wilayah lain.

Pertimbangan berikut berlaku untuk tabel global MRSC:
+ Time to Live (TTL) tidak didukung untuk tabel global MRSC.
+ Indeks sekunder lokal (LSIs) tidak didukung untuk tabel global MRSC.
+ CloudWatch Informasi Wawasan Kontributor hanya dilaporkan untuk Wilayah tempat operasi terjadi.

## Memilih mode konsistensi
<a name="V2globaltables_HowItWorks.choosing-consistency-mode"></a>

Kriteria utama untuk memilih mode konsistensi Multi-region adalah apakah aplikasi Anda memprioritaskan penulisan latensi yang lebih rendah dan pembacaan yang sangat konsisten, atau memprioritaskan konsistensi global yang kuat.

Tabel global MREC akan memiliki latensi tulis yang lebih rendah dan latensi baca yang sangat konsisten dibandingkan dengan tabel global MRSC. Tabel global MREC memiliki Recovery Point Objective (RPO) sama dengan penundaan replikasi antara replika, biasanya beberapa detik tergantung pada Regions replika.

Anda harus menggunakan mode MREC ketika:
+ Aplikasi Anda dapat mentolerir data basi yang dikembalikan dari operasi pembacaan yang sangat konsisten jika data tersebut diperbarui di Wilayah lain.
+ Anda memprioritaskan penulisan yang lebih rendah dan latensi baca yang sangat konsisten daripada konsistensi baca Multi-wilayah.
+ Strategi ketersediaan tinggi Multi-wilayah Anda dapat mentolerir RPO yang lebih besar dari nol.

Tabel global MRSC akan memiliki latensi baca tulis yang lebih tinggi dan sangat konsisten dibandingkan dengan tabel global MREC. Tabel global MRSC mendukung Recovery Point Objective (RPO) nol.

Anda harus menggunakan mode MRSC ketika:
+ Anda membutuhkan pembacaan yang sangat konsisten di beberapa Wilayah.
+ Anda memprioritaskan konsistensi baca global daripada latensi tulis yang lebih rendah.
+ Strategi ketersediaan tinggi Multi-wilayah Anda membutuhkan RPO nol.

## Memantau tabel global
<a name="monitoring-global-tables"></a>

Tabel global yang dikonfigurasi untuk konsistensi akhir Multi-wilayah (MREC) mempublikasikan metrik ke. [`ReplicationLatency`](metrics-dimensions.md#ReplicationLatency) CloudWatch Metrik ini melacak waktu yang telah berlalu antara saat item ditulis ke tabel replika, dan kapan item itu muncul di replika lain di tabel global. `ReplicationLatency`dinyatakan dalam milidetik dan dipancarkan untuk setiap pasangan Wilayah sumber dan tujuan dalam tabel global. 

`ReplicationLatency`Nilai tipikal tergantung pada jarak antara AWS Wilayah yang Anda pilih, serta variabel lain seperti jenis beban kerja dan throughput. Misalnya, replika sumber di Wilayah AS Barat (California Utara) (us-west-1) memiliki lebih rendah `ReplicationLatency` ke Wilayah Barat AS (Oregon) (us-west-2) dibandingkan dengan Wilayah Afrika (Cape Town) (af-south-1).

Nilai yang meningkat untuk `ReplicationLatency` dapat menunjukkan bahwa pembaruan dari satu replika tidak menyebar ke tabel replika lain secara tepat waktu. Dalam hal ini, Anda dapat mengalihkan sementara aktivitas baca dan tulis aplikasi Anda ke AWS Wilayah yang berbeda.

Tabel global yang dikonfigurasi untuk konsistensi kuat Multi-wilayah (MRSC) tidak mempublikasikan metrik. `ReplicationLatency`

## Pengujian injeksi kesalahan
<a name="fault-injection-testing"></a>

Baik tabel global MREC dan MRSC terintegrasi dengan [AWSAWS Fault Injection Service](https://docs.aws.amazon.com/resilience-hub/latest/userguide/testing.html) (FIS), layanan yang dikelola sepenuhnya untuk menjalankan eksperimen injeksi kesalahan terkontrol untuk meningkatkan ketahanan aplikasi. Menggunakan AWS FIS, Anda dapat:
+ Buat templat eksperimen yang menentukan skenario kegagalan tertentu.
+ Menyuntikkan kegagalan untuk memvalidasi ketahanan aplikasi dengan mensimulasikan isolasi Wilayah (yaitu, menjeda replikasi ke dan dari replika yang dipilih) untuk menguji penanganan kesalahan, mekanisme pemulihan, dan perilaku pergeseran lalu lintas multi-wilayah ketika satu Wilayah mengalami gangguan. AWS 

Misalnya, dalam tabel global dengan replika di AS Timur (Virginia N.), AS Timur (Ohio), dan AS Barat (Oregon), Anda dapat menjalankan eksperimen di AS Timur (Ohio) untuk menguji isolasi wilayah di sana sementara AS Timur (Virginia N.) dan AS Barat (Oregon) melanjutkan operasi normal. Pengujian terkontrol ini membantu Anda mengidentifikasi dan menyelesaikan masalah potensial sebelum memengaruhi beban kerja produksi. 

Lihat [Target tindakan](https://docs.aws.amazon.com/fis/latest/userguide/action-sequence.html#action-targets) dalam *panduan pengguna AWS FIS* untuk daftar lengkap tindakan yang didukung AWS FIS dan [Konektivitas Lintas Wilayah](https://docs.aws.amazon.com/fis/latest/userguide/cross-region-scenario.html) untuk menjeda replikasi DynamoDB antar wilayah.

*Untuk informasi tentang tindakan tabel global Amazon DynamoDB yang tersedia AWS di FIS, [lihat referensi tindakan tabel global DynamoDB di Panduan Pengguna FIS](https://docs.aws.amazon.com/fis/latest/userguide/fis-actions-reference.html#dynamodb-actions-reference).AWS *

Untuk mulai menjalankan eksperimen injeksi kesalahan, lihat [Merencanakan eksperimen AWS FIS Anda](https://docs.aws.amazon.com/fis/latest/userguide/getting-started-planning.html) di panduan pengguna AWS FIS.

**catatan**  
Selama AWS FIS percobaan di MRSC, pembacaan yang konsisten pada akhirnya diizinkan, tetapi pembaruan pengaturan tabel - seperti mengubah mode penagihan atau mengonfigurasi throughput tabel - tidak diizinkan, mirip dengan MREC. Silakan periksa CloudWatch metrik [`FaultInjectionServiceInducedErrors`](metrics-dimensions.md#FaultInjectionServiceInducedErrors)untuk detail tambahan mengenai kode kesalahan.

## Waktu Untuk Tayang (TTL)
<a name="global-tables-ttl"></a>

Tabel global yang dikonfigurasi untuk dukungan MREC mengonfigurasi penghapusan [Time To Live](TTL.md) (TTL). Pengaturan TTL secara otomatis disinkronkan untuk semua replika dalam tabel global. Ketika TTL menghapus item dari replika di Wilayah, penghapusan direplikasi ke semua replika lain di tabel global. TTL tidak menggunakan kapasitas tulis, jadi Anda tidak dikenakan biaya untuk penghapusan TTL di Wilayah tempat penghapusan terjadi. Namun, Anda dikenakan biaya untuk penghapusan yang direplikasi di setiap wilayah lain dengan replika di tabel global.

Replikasi penghapusan TTL mengkonsumsi kapasitas tulis pada replika tempat penghapusan direplikasi. Replika yang dikonfigurasi untuk kapasitas yang disediakan dapat membatasi permintaan jika kombinasi throughput tulis dan throughput penghapusan TTL lebih tinggi daripada kapasitas tulis yang disediakan.

Tabel global yang dikonfigurasi untuk konsistensi kuat Multi-wilayah (MRSC) tidak mendukung konfigurasi penghapusan Time To Live (TTL).

## Pengaliran
<a name="global-tables-streams"></a>

Tabel global yang dikonfigurasi untuk konsistensi akhir Multi-wilayah (MREC) mereplikasi perubahan dengan membaca perubahan tersebut dari [DynamoDB Stream](Streams.md) pada tabel replika dan menerapkan perubahan itu ke semua tabel replika lainnya. Oleh karena itu, aliran diaktifkan secara default pada semua replika dalam tabel global MREC, dan tidak dapat dinonaktifkan pada replika tersebut. Proses replikasi MREC dapat menggabungkan beberapa perubahan dalam waktu singkat menjadi satu penulisan yang direplikasi, sehingga setiap Stream replika berisi catatan yang sedikit berbeda. Catatan aliran pada replika MREC selalu diurutkan berdasarkan per item, tetapi urutan antar item mungkin berbeda antar replika.

Tabel global yang dikonfigurasi untuk Multi-region strong consistency (MRSC) tidak menggunakan DynamoDB Streams untuk replikasi, sehingga Streams tidak diaktifkan secara default pada replika MRSC. Anda dapat mengaktifkan Streams pada replika MRSC. Catatan aliran pada replika MRSC identik untuk setiap replika, termasuk urutan rekaman Stream.

Jika Anda ingin menulis aplikasi yang memproses catatan Streams untuk perubahan yang terjadi di Wilayah tertentu tetapi tidak Wilayah lain dalam tabel global, Anda dapat menambahkan atribut ke setiap item yang menentukan di Wilayah mana perubahan untuk item tersebut terjadi. Anda dapat menggunakan atribut ini untuk memfilter catatan Streams untuk perubahan yang terjadi di Wilayah lain, termasuk penggunaan filter peristiwa Lambda untuk hanya memanggil fungsi Lambda untuk perubahan di Wilayah tertentu.

## Transaksi
<a name="global-tables-transactions"></a>

Pada tabel global yang dikonfigurasi untuk MREC, operasi transaksi DynamoDB ([https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html)dan [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html)) hanya atom dalam Wilayah tempat operasi dipanggil. Penulisan transaksional tidak direplikasi sebagai unit di seluruh Wilayah, yang berarti hanya beberapa penulisan dalam transaksi yang dapat dikembalikan oleh operasi baca di replika lain pada titik waktu tertentu.

Misalnya, jika Anda memiliki tabel global dengan replika di Wilayah AS Timur (Ohio) dan AS Barat (Oregon) dan melakukan `TransactWriteItems` operasi di Wilayah AS Timur (Ohio), Anda dapat mengamati transaksi yang diselesaikan sebagian di Wilayah Barat AS (Oregon) saat perubahan direplikasi. Perubahan hanya akan direplikasi ke Wilayah lain setelah dilakukan di Wilayah sumber.

Tabel global yang dikonfigurasi untuk konsistensi kuat Multi-wilayah (MRSC) tidak mendukung operasi transaksi, dan akan mengembalikan kesalahan jika operasi tersebut dipanggil pada replika MRSC.

## Throughput baca dan tulis
<a name="V2globaltables_HowItWorks.Throughput"></a>

### Mode yang disediakan
<a name="gt_throughput.provisioned"></a>

Replikasi mengkonsumsi kapasitas tulis. Replika yang dikonfigurasi untuk kapasitas yang disediakan dapat membatasi permintaan jika kombinasi throughput penulisan aplikasi dan throughput penulisan replikasi melebihi kapasitas penulisan yang disediakan. Untuk tabel global yang menggunakan mode yang disediakan, pengaturan penskalaan otomatis untuk kapasitas baca dan tulis disinkronkan antar replika.

Anda dapat secara independen mengonfigurasi pengaturan kapasitas baca untuk setiap replika dalam tabel global dengan menggunakan [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ProvisionedThroughputOverride.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ProvisionedThroughputOverride.html)parameter di tingkat replika. Secara default, perubahan pada kapasitas baca yang disediakan diterapkan ke semua replika dalam tabel global. Saat menambahkan replika baru ke tabel global, kapasitas baca tabel sumber atau replika digunakan sebagai nilai awal kecuali penggantian tingkat replika ditentukan secara eksplisit.

### Mode sesuai permintaan
<a name="gt_throughput.on-demand"></a>

Untuk tabel global yang dikonfigurasi untuk mode sesuai permintaan, kapasitas tulis secara otomatis disinkronkan di semua replika. DynamoDB secara otomatis menyesuaikan kapasitas berdasarkan lalu lintas, dan tidak ada pengaturan kapasitas baca atau tulis khusus replika untuk dikelola.

## Pengaturan sinkronisasi
<a name="V2globaltables_HowItWorks.setting-synchronization"></a>

Pengaturan dalam tabel global DynamoDB adalah parameter konfigurasi yang mengontrol berbagai aspek perilaku tabel dan replikasi. Pengaturan ini dikelola melalui APIs bidang kontrol DynamoDB dan dapat dikonfigurasi saat membuat atau memodifikasi tabel global. Tabel global secara otomatis menyinkronkan pengaturan tertentu di semua replika untuk menjaga konsistensi, sekaligus memungkinkan fleksibilitas untuk pengoptimalan khusus wilayah. Memahami pengaturan mana yang disinkronkan dan bagaimana perilakunya membantu Anda mengonfigurasi tabel global Anda secara efektif. Pengaturan jatuh ke dalam tiga kategori utama berdasarkan bagaimana mereka disinkronkan di seluruh replika.

Pengaturan berikut selalu disinkronkan antara replika dalam tabel global:
+ Mode kapasitas (kapasitas yang disediakan atau sesuai permintaan)
+ Tabel menyediakan kapasitas tulis
+ Tabel tulis penskalaan otomatis
+ Definisi atribut skema kunci
+ Definisi Indeks Sekunder Global (GSI)
+ GSI menyediakan kapasitas tulis
+ GSI tulis penskalaan otomatis
+ Jenis Enkripsi sisi server (SSE)
+ Definisi aliran dalam mode MREC
+ Waktu Untuk Tayang (TTL)
+ Throughput Hangat
+ Throughput penulisan maksimum sesuai permintaan

Pengaturan berikut disinkronkan antara replika, tetapi dapat diganti berdasarkan per-replika:
+ Tabel menyediakan kapasitas baca
+ Tabel baca penskalaan otomatis
+ GSI menyediakan kapasitas baca
+ GSI baca penskalaan otomatis
+ Kelas Tabel
+ Throughput baca maksimum sesuai permintaan

**catatan**  
Nilai pengaturan yang dapat diganti diubah jika pengaturan dimodifikasi pada replika lainnya. Sebagai contoh, Anda memiliki tabel global MREC dengan replika di US East (Virginia N.) dan US West (Oregon). Replika US East (Virginia N.) telah menyediakan throughput baca yang disetel ke 200. RCUs Replika di US West (Oregon) memiliki override throughput baca yang disediakan disetel ke 100. RCUs Jika Anda memperbarui pengaturan throughput baca yang disediakan pada replika US East (Virginia N.) dari 200 RCUs menjadi 300 RCUs, nilai throughput baca baru yang disediakan juga akan diterapkan ke replika di US West (Oregon). Ini mengubah pengaturan throughput baca yang disediakan untuk replika AS Barat (Oregon) dari nilai penggantian 100 ke nilai baru 300. RCUs RCUs

Pengaturan berikut tidak pernah disinkronkan antara replika:
+ Perlindungan penghapusan
+ Point-in-time Pemulihan
+ Tag
+ Pemberdayaan Wawasan CloudWatch Kontributor Tabel
+ Pemberdayaan Wawasan CloudWatch Kontributor GSI
+ Definisi Kinesis Data Streams
+ Kebijakan Sumber Daya
+ Definisi aliran dalam mode MRSC

Semua pengaturan lain tidak disinkronkan antara replika.

## DynamoDB Accelerator (DAX)
<a name="V2globaltables_HowItWorks.dax"></a>

Menulis ke replika tabel global melewati DynamoDB Accelerator (DAX), memperbarui DynamoDB secara langsung. Akibatnya, cache DAX dapat menjadi basi karena penulisan tidak memperbarui cache DAX. Cache DAX yang dikonfigurasi untuk replika tabel global hanya akan disegarkan ketika TTL cache kedaluwarsa.

## Pertimbangan untuk mengelola tabel global
<a name="management-considerations"></a>

Anda tidak dapat menghapus tabel yang digunakan untuk menambahkan replika tabel global baru hingga 24 jam berlalu sejak replika baru dibuat.

Jika Anda menonaktifkan AWS Wilayah yang berisi replika tabel global, replika tersebut akan dikonversi secara permanen ke tabel Wilayah tunggal 20 jam setelah Wilayah dinonaktifkan.

# Tutorial: Membuat tabel global
<a name="V2globaltables.tutorial"></a>

Bagian ini memberikan step-by-step petunjuk untuk membuat tabel global DynamoDB yang dikonfigurasi untuk mode konsistensi pilihan Anda. Pilih mode Konsistensi Akhir Multi-Region (MREC) atau Multi-Region Strong Consistency (MRSC) berdasarkan kebutuhan aplikasi Anda.

Tabel global MREC memberikan latensi tulis yang lebih rendah dengan konsistensi akhirnya. Wilayah AWS Tabel global MRSC memberikan pembacaan yang sangat konsisten di seluruh Wilayah dengan latensi tulis yang sedikit lebih tinggi daripada MREC. Pilih mode konsistensi yang paling sesuai dengan kebutuhan aplikasi Anda untuk konsistensi, latensi, dan ketersediaan data.

**Topics**
+ [Membuat tabel global yang dikonfigurasi untuk MREC](#V2creategt_mrec)
+ [Membuat tabel global yang dikonfigurasi untuk MRSC](#create-gt-mrsc)

## Membuat tabel global yang dikonfigurasi untuk MREC
<a name="V2creategt_mrec"></a>

Bagian ini menunjukkan cara membuat tabel global dengan mode Multi-Region Eventual Consistency (MREC). MREC adalah mode konsistensi default untuk tabel global dan menyediakan penulisan latensi rendah dengan replikasi asinkron. Wilayah AWS Perubahan yang dilakukan pada item di satu wilayah biasanya direplikasi ke semua wilayah lain dalam satu detik. Hal ini membuat MREC ideal untuk aplikasi yang memprioritaskan latensi tulis rendah dan dapat mentolerir periode singkat di mana Wilayah yang berbeda dapat mengembalikan versi data yang sedikit berbeda.

Anda dapat membuat tabel global MREC dengan replika di Wilayah AWS mana pun di mana DynamoDB tersedia dan menambah atau menghapus replika kapan saja. Contoh berikut menunjukkan cara membuat tabel global MREC dengan replika di beberapa wilayah.

### Membuat tabel global MREC menggunakan DynamoDB Console
<a name="mrec-console"></a>

Ikuti langkah-langkah ini untuk membuat tabel global menggunakan Konsol Manajemen AWS. Contoh berikut membuat tabel global dengan tabel replika di Amerika Serikat dan Eropa.

1. Masuk ke Konsol Manajemen AWS dan buka konsol DynamoDB di. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Untuk contoh ini, pilih **US East (Ohio)** dari pemilih Region di bilah navigasi.

1. Di panel navigasi di sisi kiri konsol, pilih **Tabel**.

1. Pilih **Buat Tabel**.

1. Pada halaman **Buat tabel**:

   1. Untuk **Nama tabel**, masukkan **Music**.

   1. Untuk **kunci Partisi**, masukkan**Artist**.

   1. Untuk **tombol Sortir**, masukkan**SongTitle**.

   1. Simpan pengaturan default lainnya dan pilih **Buat tabel**.

      Tabel baru ini berfungsi sebagai tabel replika pertama dalam tabel global baru. Ini adalah protojenis untuk tabel replika lain yang Anda tambahkan nantinya.

1. Setelah tabel menjadi aktif:

   1. Pilih tabel **Musik** dari daftar tabel.

   1. Pilih tab **tabel Global**.

   1. Pilih **Buat replika**.

1. Dari daftar dropdown **Wilayah Replikasi yang Tersedia**, pilih **US West (Oregon)** us-west-2.

   Konsol memastikan bahwa tabel dengan nama yang sama tidak ada di Wilayah yang dipilih. Jika ada tabel dengan nama yang sama, Anda harus menghapus tabel yang ada sebelum dapat membuat tabel replika baru di Wilayah tersebut.

1. Pilih **Buat replika**. Ini memulai proses pembuatan tabel di Wilayah AS Barat (Oregon) us-west-2.

   Tab **tabel Global** untuk tabel **Musik** (dan untuk tabel replika lainnya) menunjukkan bahwa tabel telah direplikasi di beberapa Wilayah.

1. Tambahkan wilayah lain dengan mengulangi langkah-langkah sebelumnya, tetapi pilih **Eropa (Frankfurt) eu-central-1** sebagai wilayahnya.

1. Untuk menguji replikasi:

   1. Pastikan Anda menggunakan Wilayah Konsol Manajemen AWS Timur AS (Ohio).

   1. Pilih **Jelajahi item tabel**.

   1. Pilih **Buat item**.

   1. Masuk **item\$11** untuk **Artis** dan **Song Value 1** untuk **SongTitle**.

   1. Pilih **Buat item**.

1. Verifikasi replikasi dengan beralih ke wilayah lain:

   1. Dari pemilih Region di sudut kanan atas, pilih **Eropa** (Frankfurt).

   1. Verifikasi bahwa tabel **Musik** berisi item yang Anda buat.

   1. Ulangi verifikasi untuk **US West (Oregon)**.

### Membuat tabel global MREC menggunakan atau AWS CLI Java
<a name="mrec-cli-java"></a>

------
#### [ CLI ]

Contoh kode berikut menunjukkan cara mengelola tabel global DynamoDB dengan replikasi Multi-region dengan konsistensi akhirnya (MREC).
+ Buat tabel dengan Multi-region replication (MREC).
+ Masukkan dan dapatkan item dari tabel replika.
+ Hapus replika one-by-one.
+ Bersihkan dengan menghapus tabel.

**AWS CLI dengan skrip Bash**  
Buat tabel dengan replikasi Multi-region.  

```
# Step 1: Create a new table (MusicTable) in US East (Ohio), with DynamoDB Streams enabled (NEW_AND_OLD_IMAGES)
aws dynamodb create-table \
    --table-name MusicTable \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --billing-mode PAY_PER_REQUEST \
    --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES \
    --region us-east-2

# Step 2: Create an identical MusicTable table in US East (N. Virginia)
aws dynamodb update-table --table-name MusicTable --cli-input-json \
'{
  "ReplicaUpdates":
  [
    {
      "Create": {
        "RegionName": "us-east-1"
      }
    }
  ]
}' \
--region us-east-2

# Step 3: Create a table in Europe (Ireland)
aws dynamodb update-table --table-name MusicTable --cli-input-json \
'{
  "ReplicaUpdates":
  [
    {
      "Create": {
        "RegionName": "eu-west-1"
      }
    }
  ]
}' \
--region us-east-2
```
Jelaskan tabel Multi-region.  

```
# Step 4: View the list of replicas created using describe-table
aws dynamodb describe-table \
    --table-name MusicTable \
    --region us-east-2 \
    --query 'Table.{TableName:TableName,TableStatus:TableStatus,MultiRegionConsistency:MultiRegionConsistency,Replicas:Replicas[*].{Region:RegionName,Status:ReplicaStatus}}'
```
Letakkan item dalam tabel replika.  

```
# Step 5: To verify that replication is working, add a new item to the Music table in US East (Ohio)
aws dynamodb put-item \
    --table-name MusicTable \
    --item '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \
    --region us-east-2
```
Dapatkan item dari tabel replika.  

```
# Step 6: Wait for a few seconds, and then check to see whether the item has been 
# successfully replicated to US East (N. Virginia) and Europe (Ireland)
aws dynamodb get-item \
    --table-name MusicTable \
    --key '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \
    --region us-east-1

aws dynamodb get-item \
    --table-name MusicTable \
    --key '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \
    --region eu-west-1
```
Hapus replika.  

```
# Step 7: Delete the replica table in Europe (Ireland) Region
aws dynamodb update-table --table-name MusicTable --cli-input-json \
'{
  "ReplicaUpdates":
  [
    {
      "Delete": {
        "RegionName": "eu-west-1"
      }
    }
  ]
}' \
--region us-east-2

# Delete the replica table in US East (N. Virginia) Region
aws dynamodb update-table --table-name MusicTable --cli-input-json \
'{
  "ReplicaUpdates":
  [
    {
      "Delete": {
        "RegionName": "us-east-1"
      }
    }
  ]
}' \
--region us-east-2
```
Bersihkan dengan menghapus tabel.  

```
# Clean up: Delete the primary table
aws dynamodb delete-table --table-name MusicTable --region us-east-2

echo "Global table demonstration complete."
```
+ Untuk detail API, lihat topik berikut di *Referensi Perintah AWS CLI *.
  + [CreateTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/CreateTable)
  + [DeleteTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/DeleteTable)
  + [DescribeTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/DescribeTable)
  + [GetItem](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/GetItem)
  + [PutItem](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/PutItem)
  + [UpdateTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/UpdateTable)

------
#### [ Java ]

Contoh kode berikut menunjukkan cara membuat dan mengelola tabel global DynamoDB dengan replika di beberapa Wilayah.
+ Buat tabel dengan Global Secondary Index dan DynamoDB Streams.
+ Tambahkan replika di Wilayah yang berbeda untuk membuat tabel global.
+ Hapus replika dari tabel global.
+ Tambahkan item pengujian untuk memverifikasi replikasi di seluruh Wilayah.
+ Jelaskan konfigurasi tabel global dan status replika.

**SDK untuk Java 2.x**  
Buat tabel dengan Global Secondary Index dan DynamoDB Streams menggunakan. AWS SDK for Java 2.x  

```
    public static CreateTableResponse createTableWithGSI(
        final DynamoDbClient dynamoDbClient, final String tableName, final String indexName) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (indexName == null || indexName.trim().isEmpty()) {
            throw new IllegalArgumentException("Index name cannot be null or empty");
        }

        try {
            LOGGER.info("Creating table: " + tableName + " with GSI: " + indexName);

            CreateTableRequest createTableRequest = CreateTableRequest.builder()
                .tableName(tableName)
                .attributeDefinitions(
                    AttributeDefinition.builder()
                        .attributeName("Artist")
                        .attributeType(ScalarAttributeType.S)
                        .build(),
                    AttributeDefinition.builder()
                        .attributeName("SongTitle")
                        .attributeType(ScalarAttributeType.S)
                        .build())
                .keySchema(
                    KeySchemaElement.builder()
                        .attributeName("Artist")
                        .keyType(KeyType.HASH)
                        .build(),
                    KeySchemaElement.builder()
                        .attributeName("SongTitle")
                        .keyType(KeyType.RANGE)
                        .build())
                .billingMode(BillingMode.PAY_PER_REQUEST)
                .globalSecondaryIndexes(GlobalSecondaryIndex.builder()
                    .indexName(indexName)
                    .keySchema(KeySchemaElement.builder()
                        .attributeName("SongTitle")
                        .keyType(KeyType.HASH)
                        .build())
                    .projection(
                        Projection.builder().projectionType(ProjectionType.ALL).build())
                    .build())
                .streamSpecification(StreamSpecification.builder()
                    .streamEnabled(true)
                    .streamViewType(StreamViewType.NEW_AND_OLD_IMAGES)
                    .build())
                .build();

            CreateTableResponse response = dynamoDbClient.createTable(createTableRequest);
            LOGGER.info("Table creation initiated. Status: "
                + response.tableDescription().tableStatus());

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to create table: " + tableName + " - " + e.getMessage());
            throw e;
        }
    }
```
Tunggu tabel menjadi aktif menggunakan AWS SDK for Java 2.x.  

```
    public static void waitForTableActive(final DynamoDbClient dynamoDbClient, final String tableName) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }

        try {
            LOGGER.info("Waiting for table to become active: " + tableName);

            try (DynamoDbWaiter waiter =
                DynamoDbWaiter.builder().client(dynamoDbClient).build()) {
                DescribeTableRequest request =
                    DescribeTableRequest.builder().tableName(tableName).build();

                waiter.waitUntilTableExists(request);
                LOGGER.info("Table is now active: " + tableName);
            }

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to wait for table to become active: " + tableName + " - " + e.getMessage());
            throw e;
        }
    }
```
Tambahkan replika untuk membuat atau memperluas tabel global menggunakan AWS SDK for Java 2.x.  

```
    public static UpdateTableResponse addReplica(
        final DynamoDbClient dynamoDbClient,
        final String tableName,
        final Region replicaRegion,
        final String indexName,
        final Long readCapacity) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (replicaRegion == null) {
            throw new IllegalArgumentException("Replica region cannot be null");
        }
        if (indexName == null || indexName.trim().isEmpty()) {
            throw new IllegalArgumentException("Index name cannot be null or empty");
        }
        if (readCapacity == null || readCapacity <= 0) {
            throw new IllegalArgumentException("Read capacity must be a positive number");
        }

        try {
            LOGGER.info("Adding replica in region: " + replicaRegion.id() + " for table: " + tableName);

            // Create a ReplicationGroupUpdate for adding a replica
            ReplicationGroupUpdate replicationGroupUpdate = ReplicationGroupUpdate.builder()
                .create(builder -> builder.regionName(replicaRegion.id())
                    .globalSecondaryIndexes(ReplicaGlobalSecondaryIndex.builder()
                        .indexName(indexName)
                        .provisionedThroughputOverride(ProvisionedThroughputOverride.builder()
                            .readCapacityUnits(readCapacity)
                            .build())
                        .build())
                    .build())
                .build();

            UpdateTableRequest updateTableRequest = UpdateTableRequest.builder()
                .tableName(tableName)
                .replicaUpdates(replicationGroupUpdate)
                .build();

            UpdateTableResponse response = dynamoDbClient.updateTable(updateTableRequest);
            LOGGER.info("Replica addition initiated in region: " + replicaRegion.id());

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to add replica in region: " + replicaRegion.id() + " - " + e.getMessage());
            throw e;
        }
    }
```
Hapus replika dari tabel global menggunakan AWS SDK for Java 2.x.  

```
    public static UpdateTableResponse removeReplica(
        final DynamoDbClient dynamoDbClient, final String tableName, final Region replicaRegion) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (replicaRegion == null) {
            throw new IllegalArgumentException("Replica region cannot be null");
        }

        try {
            LOGGER.info("Removing replica in region: " + replicaRegion.id() + " for table: " + tableName);

            // Create a ReplicationGroupUpdate for removing a replica
            ReplicationGroupUpdate replicationGroupUpdate = ReplicationGroupUpdate.builder()
                .delete(builder -> builder.regionName(replicaRegion.id()).build())
                .build();

            UpdateTableRequest updateTableRequest = UpdateTableRequest.builder()
                .tableName(tableName)
                .replicaUpdates(replicationGroupUpdate)
                .build();

            UpdateTableResponse response = dynamoDbClient.updateTable(updateTableRequest);
            LOGGER.info("Replica removal initiated in region: " + replicaRegion.id());

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to remove replica in region: " + replicaRegion.id() + " - " + e.getMessage());
            throw e;
        }
    }
```
Tambahkan item pengujian untuk memverifikasi replikasi menggunakan AWS SDK for Java 2.x.  

```
    public static PutItemResponse putTestItem(
        final DynamoDbClient dynamoDbClient, final String tableName, final String artist, final String songTitle) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (artist == null || artist.trim().isEmpty()) {
            throw new IllegalArgumentException("Artist cannot be null or empty");
        }
        if (songTitle == null || songTitle.trim().isEmpty()) {
            throw new IllegalArgumentException("Song title cannot be null or empty");
        }

        try {
            LOGGER.info("Adding test item to table: " + tableName);

            Map<String, software.amazon.awssdk.services.dynamodb.model.AttributeValue> item = new HashMap<>();
            item.put(
                "Artist",
                software.amazon.awssdk.services.dynamodb.model.AttributeValue.builder()
                    .s(artist)
                    .build());
            item.put(
                "SongTitle",
                software.amazon.awssdk.services.dynamodb.model.AttributeValue.builder()
                    .s(songTitle)
                    .build());

            PutItemRequest putItemRequest =
                PutItemRequest.builder().tableName(tableName).item(item).build();

            PutItemResponse response = dynamoDbClient.putItem(putItemRequest);
            LOGGER.info("Test item added successfully");

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to add test item to table: " + tableName + " - " + e.getMessage());
            throw e;
        }
    }
```
Jelaskan konfigurasi tabel global dan replika menggunakan AWS SDK for Java 2.x.  

```
    public static DescribeTableResponse describeTable(final DynamoDbClient dynamoDbClient, final String tableName) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }

        try {
            LOGGER.info("Describing table: " + tableName);

            DescribeTableRequest request =
                DescribeTableRequest.builder().tableName(tableName).build();

            DescribeTableResponse response = dynamoDbClient.describeTable(request);

            LOGGER.info("Table status: " + response.table().tableStatus());
            if (response.table().replicas() != null
                && !response.table().replicas().isEmpty()) {
                LOGGER.info("Number of replicas: " + response.table().replicas().size());
                response.table()
                    .replicas()
                    .forEach(replica -> LOGGER.info(
                        "Replica region: " + replica.regionName() + ", Status: " + replica.replicaStatus()));
            }

            return response;

        } catch (ResourceNotFoundException e) {
            LOGGER.severe("Table not found: " + tableName + " - " + e.getMessage());
            throw e;
        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to describe table: " + tableName + " - " + e.getMessage());
            throw e;
        }
    }
```
Contoh lengkap operasi tabel global menggunakan AWS SDK for Java 2.x.  

```
    public static void exampleUsage(final Region sourceRegion, final Region replicaRegion) {

        String tableName = "Music";
        String indexName = "SongTitleIndex";
        Long readCapacity = 15L;

        // Create DynamoDB client for the source region
        try (DynamoDbClient dynamoDbClient =
            DynamoDbClient.builder().region(sourceRegion).build()) {

            try {
                // Step 1: Create the initial table with GSI and streams
                LOGGER.info("Step 1: Creating table in source region: " + sourceRegion.id());
                createTableWithGSI(dynamoDbClient, tableName, indexName);

                // Step 2: Wait for table to become active
                LOGGER.info("Step 2: Waiting for table to become active");
                waitForTableActive(dynamoDbClient, tableName);

                // Step 3: Add replica in destination region
                LOGGER.info("Step 3: Adding replica in region: " + replicaRegion.id());
                addReplica(dynamoDbClient, tableName, replicaRegion, indexName, readCapacity);

                // Step 4: Wait a moment for replica creation to start
                Thread.sleep(5000);

                // Step 5: Describe table to view replica information
                LOGGER.info("Step 5: Describing table to view replicas");
                describeTable(dynamoDbClient, tableName);

                // Step 6: Add a test item to verify replication
                LOGGER.info("Step 6: Adding test item to verify replication");
                putTestItem(dynamoDbClient, tableName, "TestArtist", "TestSong");

                LOGGER.info("Global table setup completed successfully!");
                LOGGER.info("You can verify replication by checking the item in region: " + replicaRegion.id());

                // Step 7: Remove replica and clean up table
                LOGGER.info("Step 7: Removing replica from region: " + replicaRegion.id());
                removeReplica(dynamoDbClient, tableName, replicaRegion);
                DeleteTableResponse deleteTableResponse = dynamoDbClient.deleteTable(
                    DeleteTableRequest.builder().tableName(tableName).build());
                LOGGER.info("MREC global table demonstration completed successfully!");

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Thread was interrupted", e);
            } catch (DynamoDbException e) {
                LOGGER.severe("DynamoDB operation failed: " + e.getMessage());
                throw e;
            }
        }
    }
```
+ Untuk detail API, lihat topik berikut di *Referensi API AWS SDK for Java 2.x *.
  + [CreateTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/CreateTable)
  + [DescribeTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/DescribeTable)
  + [PutItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/PutItem)
  + [UpdateTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateTable)

------

## Membuat tabel global yang dikonfigurasi untuk MRSC
<a name="create-gt-mrsc"></a>

Bagian ini menunjukkan cara membuat tabel global Multi-Region Strong Consistency (MRSC). Tabel global MRSC secara sinkron mereplikasi perubahan item di seluruh Wilayah, memastikan bahwa operasi pembacaan yang sangat konsisten pada replika apa pun selalu mengembalikan versi terbaru dari suatu item. Saat mengonversi tabel Single-region ke tabel global MRSC, Anda harus memastikan bahwa tabel tersebut kosong. Mengonversi tabel wilayah Tunggal ke tabel global MRSC dengan item yang ada tidak didukung. Pastikan tidak ada data yang ditulis ke dalam tabel selama proses konversi.

Anda dapat mengonfigurasi tabel global MRSC dengan tiga replika, atau dua replika dan satu saksi. Saat membuat tabel global MRSC, Anda memilih Wilayah tempat replika dan saksi opsional digunakan. Contoh berikut membuat tabel global MRSC dengan replika di Wilayah AS Timur (Virginia N.) dan Timur AS (Ohio), dengan saksi di Wilayah AS Barat (Oregon).

**catatan**  
Sebelum membuat tabel global, verifikasi bahwa batas throughput Kuota Layanan konsisten di semua Wilayah target, karena ini diperlukan untuk membuat tabel global. Untuk informasi selengkapnya tentang batas throughput tabel global, lihat [Kuota tabel global](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ServiceQuotas.html#gt-limits-throughput).

### Membuat tabel global MRSC menggunakan DynamoDB Console
<a name="mrsc_console"></a>

Ikuti langkah-langkah ini untuk membuat tentang tabel global MRSC menggunakan. Konsol Manajemen AWS

1. Masuk ke Konsol Manajemen AWS dan buka konsol DynamoDB di. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Dari pemilih Region di bilah navigasi, pilih Wilayah di mana tabel global dengan MRSC [didukung](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes), seperti. **us-east-2**

1. Di panel navigasi, pilih **Tabel**.

1. Pilih **Buat tabel**.

1. Pada halaman **Buat tabel**:

   1. Untuk **Nama tabel**, masukkan **Music**.

   1. Untuk **kunci Partition**, masukkan **Artist** dan simpan tipe **String** default.

   1. Untuk **tombol Sort**, masukkan **SongTitle** dan simpan tipe **String** default.

   1. Simpan pengaturan default lainnya dan pilih **Buat tabel**

      Tabel baru ini berfungsi sebagai tabel replika pertama dalam tabel global baru. Ini adalah protojenis untuk tabel replika lain yang Anda tambahkan nantinya.

1. Tunggu tabel menjadi aktif, lalu pilih dari daftar tabel.

1. Pilih tab **tabel Global**, lalu pilih **Buat replika**.

1. Pada halaman **Buat replika**:

   1. Di bawah **Konsistensi Multi-Region**, pilih **Konsistensi yang kuat**.

   1. Untuk **Wilayah Replikasi 1**, pilih**US East (N. Virginia) us-east-1**.

   1. Untuk **Wilayah Replikasi 2**, pilih**US West (Oregon) us-west-2**.

   1. Periksa **Konfigurasi sebagai Saksi** untuk wilayah AS Barat (Oregon).

   1. Pilih **Buat replika**.

1. Tunggu proses pembuatan replika dan saksi selesai. Status replika akan ditampilkan sebagai **Aktif** saat tabel siap digunakan.

### Membuat tabel global MRSC menggunakan AWS CLI atau Java
<a name="mrsc-cli-java"></a>

Sebelum memulai, pastikan bahwa kepala IAM Anda memiliki izin yang diperlukan untuk membuat tabel global MRSC dengan Wilayah saksi.

Contoh kebijakan IAM berikut memungkinkan Anda membuat tabel DynamoDB () di AS Timur `MusicTable` (Ohio) dengan replika di AS Timur (Virginia N.) dan Wilayah saksi di AS Barat (Oregon):

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:CreateTable",
                "dynamodb:CreateTableReplica",
                "dynamodb:CreateGlobalTableWitness",
                "dynamodb:DescribeTable",
                "dynamodb:UpdateTable",
                "dynamodb:DeleteTable",
                "dynamodb:DeleteTableReplica",
                "dynamodb:DeleteGlobalTableWitness",
                "dynamodb:Scan",
                "dynamodb:Query",
                "dynamodb:UpdateItem",
                "dynamodb:PutItem",
                "dynamodb:GetItem",
                "dynamodb:DeleteItem",
                "dynamodb:BatchWriteItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:us-east-1:123456789012:table/MusicTable",
                "arn:aws:dynamodb:us-east-2:123456789012:table/MusicTable",
                "arn:aws:dynamodb:us-west-2:123456789012:table/MusicTable"
            ]
        },
        {
            "Effect": "Allow",
            "Action": "iam:CreateServiceLinkedRole",
            "Resource": "arn:aws:iam::*:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication",
            "Condition": {
                "StringLike": {
                    "iam:AWSServiceName": "replication.dynamodb.amazonaws.com"
                }
            }
        }
    ]
}
```

------

Contoh kode berikut menunjukkan cara membuat dan mengelola tabel global DynamoDB dengan Multi-Region Strong Consistency (MRSC).
+ Buat tabel dengan Konsistensi Kuat Multi-Region.
+ Verifikasi konfigurasi MRSC dan status replika.
+ Uji konsistensi yang kuat di seluruh Wilayah dengan pembacaan langsung.
+ Lakukan penulisan bersyarat dengan jaminan MRSC.
+ Bersihkan sumber daya tabel global MRSC.

------
#### [ Bash ]

**AWS CLI dengan skrip Bash**  
Buat tabel dengan Konsistensi Kuat Multi-Region.  

```
# Step 1: Create a new table in us-east-2 (primary region for MRSC)
# Note: Table must be empty when enabling MRSC
aws dynamodb create-table \
    --table-name MusicTable \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --billing-mode PAY_PER_REQUEST \
    --region us-east-2

# Wait for table to become active
aws dynamodb wait table-exists --table-name MusicTable --region us-east-2

# Step 2: Add replica and witness with Multi-Region Strong Consistency
# MRSC requires exactly three replicas in supported regions
aws dynamodb update-table \
    --table-name MusicTable \
    --replica-updates '[{"Create": {"RegionName": "us-east-1"}}]' \
    --global-table-witness-updates '[{"Create": {"RegionName": "us-west-2"}}]' \
    --multi-region-consistency STRONG \
    --region us-east-2
```
Verifikasi konfigurasi MRSC dan status replika.  

```
# Verify the global table configuration and MRSC setting
aws dynamodb describe-table \
    --table-name MusicTable \
    --region us-east-2 \
    --query 'Table.{TableName:TableName,TableStatus:TableStatus,MultiRegionConsistency:MultiRegionConsistency,Replicas:Replicas[*],GlobalTableWitnesses:GlobalTableWitnesses[*].{Region:RegionName,Status:ReplicaStatus}}'
```
Uji konsistensi yang kuat dengan pembacaan langsung di seluruh Wilayah.  

```
# Write an item to the primary region
aws dynamodb put-item \
    --table-name MusicTable \
    --item '{"Artist": {"S":"The Beatles"},"SongTitle": {"S":"Hey Jude"},"Album": {"S":"The Beatles 1967-1970"},"Year": {"N":"1968"}}' \
    --region us-east-2

# Read the item from replica region to verify strong consistency (cannot read or write to witness)
# No wait time needed - MRSC provides immediate consistency
echo "Reading from us-east-1 (immediate consistency):"
aws dynamodb get-item \
    --table-name MusicTable \
    --key '{"Artist": {"S":"The Beatles"},"SongTitle": {"S":"Hey Jude"}}' \
    --consistent-read \
    --region us-east-1
```
Lakukan penulisan bersyarat dengan jaminan MRSC.  

```
# Perform a conditional update from a different region
# This demonstrates that conditions work consistently across all regions
aws dynamodb update-item \
    --table-name MusicTable \
    --key '{"Artist": {"S":"The Beatles"},"SongTitle": {"S":"Hey Jude"}}' \
    --update-expression "SET #rating = :rating" \
    --condition-expression "attribute_exists(Artist)" \
    --expression-attribute-names '{"#rating": "Rating"}' \
    --expression-attribute-values '{":rating": {"N":"5"}}' \
    --region us-east-1
```
Bersihkan sumber daya tabel global MRSC.  

```
# Remove replica tables (must be done before deleting the primary table)
aws dynamodb update-table \
    --table-name MusicTable \
    --replica-updates '[{"Delete": {"RegionName": "us-east-1"}}]' \
    --global-table-witness-updates '[{"Delete": {"RegionName": "us-west-2"}}]' \
    --region us-east-2

# Wait for replicas to be deleted
echo "Waiting for replicas to be deleted..."
sleep 30

# Delete the primary table
aws dynamodb delete-table \
    --table-name MusicTable \
    --region us-east-2
```
+ Untuk detail API, lihat topik berikut di *Referensi Perintah AWS CLI *.
  + [CreateTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/CreateTable)
  + [DeleteTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/DeleteTable)
  + [DescribeTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/DescribeTable)
  + [GetItem](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/GetItem)
  + [PutItem](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/PutItem)
  + [UpdateItem](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/UpdateItem)
  + [UpdateTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/UpdateTable)

------
#### [ Java ]

**SDK untuk Java 2.x**  
Buat tabel regional yang siap untuk konversi MRSC menggunakan AWS SDK for Java 2.x.  

```
    public static CreateTableResponse createRegionalTable(final DynamoDbClient dynamoDbClient, final String tableName) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }

        try {
            LOGGER.info("Creating regional table: " + tableName + " (must be empty for MRSC)");

            CreateTableRequest createTableRequest = CreateTableRequest.builder()
                .tableName(tableName)
                .attributeDefinitions(
                    AttributeDefinition.builder()
                        .attributeName("Artist")
                        .attributeType(ScalarAttributeType.S)
                        .build(),
                    AttributeDefinition.builder()
                        .attributeName("SongTitle")
                        .attributeType(ScalarAttributeType.S)
                        .build())
                .keySchema(
                    KeySchemaElement.builder()
                        .attributeName("Artist")
                        .keyType(KeyType.HASH)
                        .build(),
                    KeySchemaElement.builder()
                        .attributeName("SongTitle")
                        .keyType(KeyType.RANGE)
                        .build())
                .billingMode(BillingMode.PAY_PER_REQUEST)
                .build();

            CreateTableResponse response = dynamoDbClient.createTable(createTableRequest);
            LOGGER.info("Regional table creation initiated. Status: "
                + response.tableDescription().tableStatus());

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to create regional table: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to create regional table: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Konversikan tabel regional ke MRSC dengan replika dan saksi menggunakan. AWS SDK for Java 2.x  

```
    public static UpdateTableResponse convertToMRSCWithWitness(
        final DynamoDbClient dynamoDbClient,
        final String tableName,
        final Region replicaRegion,
        final Region witnessRegion) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (replicaRegion == null) {
            throw new IllegalArgumentException("Replica region cannot be null");
        }
        if (witnessRegion == null) {
            throw new IllegalArgumentException("Witness region cannot be null");
        }

        try {
            LOGGER.info("Converting table to MRSC with replica in " + replicaRegion.id() + " and witness in "
                + witnessRegion.id());

            // Create replica update using ReplicationGroupUpdate
            ReplicationGroupUpdate replicaUpdate = ReplicationGroupUpdate.builder()
                .create(CreateReplicationGroupMemberAction.builder()
                    .regionName(replicaRegion.id())
                    .build())
                .build();

            // Create witness update
            GlobalTableWitnessGroupUpdate witnessUpdate = GlobalTableWitnessGroupUpdate.builder()
                .create(CreateGlobalTableWitnessGroupMemberAction.builder()
                    .regionName(witnessRegion.id())
                    .build())
                .build();

            UpdateTableRequest updateTableRequest = UpdateTableRequest.builder()
                .tableName(tableName)
                .replicaUpdates(List.of(replicaUpdate))
                .globalTableWitnessUpdates(List.of(witnessUpdate))
                .multiRegionConsistency(MultiRegionConsistency.STRONG)
                .build();

            UpdateTableResponse response = dynamoDbClient.updateTable(updateTableRequest);
            LOGGER.info("MRSC conversion initiated. Status: "
                + response.tableDescription().tableStatus());
            LOGGER.info("UpdateTableResponse full object: " + response);
            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to convert table to MRSC: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to convert table to MRSC: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Jelaskan konfigurasi tabel global MRSC menggunakan AWS SDK for Java 2.x.  

```
    public static DescribeTableResponse describeMRSCTable(final DynamoDbClient dynamoDbClient, final String tableName) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }

        try {
            LOGGER.info("Describing MRSC global table: " + tableName);

            DescribeTableRequest request =
                DescribeTableRequest.builder().tableName(tableName).build();

            DescribeTableResponse response = dynamoDbClient.describeTable(request);

            LOGGER.info("Table status: " + response.table().tableStatus());
            LOGGER.info("Multi-region consistency: " + response.table().multiRegionConsistency());

            if (response.table().replicas() != null
                && !response.table().replicas().isEmpty()) {
                LOGGER.info("Number of replicas: " + response.table().replicas().size());
                response.table()
                    .replicas()
                    .forEach(replica -> LOGGER.info(
                        "Replica region: " + replica.regionName() + ", Status: " + replica.replicaStatus()));
            }

            if (response.table().globalTableWitnesses() != null
                && !response.table().globalTableWitnesses().isEmpty()) {
                LOGGER.info("Number of witnesses: "
                    + response.table().globalTableWitnesses().size());
                response.table()
                    .globalTableWitnesses()
                    .forEach(witness -> LOGGER.info(
                        "Witness region: " + witness.regionName() + ", Status: " + witness.witnessStatus()));
            }

            return response;

        } catch (ResourceNotFoundException e) {
            LOGGER.severe("Table not found: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Table not found: " + tableName)
                .cause(e)
                .build();
        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to describe table: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to describe table: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Tambahkan item pengujian untuk memverifikasi konsistensi kuat MRSC menggunakan AWS SDK for Java 2.x.  

```
    public static PutItemResponse putTestItem(
        final DynamoDbClient dynamoDbClient,
        final String tableName,
        final String artist,
        final String songTitle,
        final String album,
        final String year) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (artist == null || artist.trim().isEmpty()) {
            throw new IllegalArgumentException("Artist cannot be null or empty");
        }
        if (songTitle == null || songTitle.trim().isEmpty()) {
            throw new IllegalArgumentException("Song title cannot be null or empty");
        }

        try {
            LOGGER.info("Adding test item to MRSC global table: " + tableName);

            Map<String, AttributeValue> item = new HashMap<>();
            item.put("Artist", AttributeValue.builder().s(artist).build());
            item.put("SongTitle", AttributeValue.builder().s(songTitle).build());

            if (album != null && !album.trim().isEmpty()) {
                item.put("Album", AttributeValue.builder().s(album).build());
            }
            if (year != null && !year.trim().isEmpty()) {
                item.put("Year", AttributeValue.builder().n(year).build());
            }

            PutItemRequest putItemRequest =
                PutItemRequest.builder().tableName(tableName).item(item).build();

            PutItemResponse response = dynamoDbClient.putItem(putItemRequest);
            LOGGER.info("Test item added successfully with strong consistency");

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to add test item to table: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to add test item to table: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Baca item dengan pembacaan konsisten dari replika MRSC menggunakan. AWS SDK for Java 2.x  

```
    public static GetItemResponse getItemWithConsistentRead(
        final DynamoDbClient dynamoDbClient, final String tableName, final String artist, final String songTitle) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (artist == null || artist.trim().isEmpty()) {
            throw new IllegalArgumentException("Artist cannot be null or empty");
        }
        if (songTitle == null || songTitle.trim().isEmpty()) {
            throw new IllegalArgumentException("Song title cannot be null or empty");
        }

        try {
            LOGGER.info("Reading item from MRSC global table with consistent read: " + tableName);

            Map<String, AttributeValue> key = new HashMap<>();
            key.put("Artist", AttributeValue.builder().s(artist).build());
            key.put("SongTitle", AttributeValue.builder().s(songTitle).build());

            GetItemRequest getItemRequest = GetItemRequest.builder()
                .tableName(tableName)
                .key(key)
                .consistentRead(true)
                .build();

            GetItemResponse response = dynamoDbClient.getItem(getItemRequest);

            if (response.hasItem()) {
                LOGGER.info("Item found with strong consistency - no wait time needed");
            } else {
                LOGGER.info("Item not found");
            }

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to read item from table: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to read item from table: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Lakukan pembaruan bersyarat dengan jaminan MRSC menggunakan. AWS SDK for Java 2.x  

```
    public static UpdateItemResponse performConditionalUpdate(
        final DynamoDbClient dynamoDbClient,
        final String tableName,
        final String artist,
        final String songTitle,
        final String rating) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (artist == null || artist.trim().isEmpty()) {
            throw new IllegalArgumentException("Artist cannot be null or empty");
        }
        if (songTitle == null || songTitle.trim().isEmpty()) {
            throw new IllegalArgumentException("Song title cannot be null or empty");
        }
        if (rating == null || rating.trim().isEmpty()) {
            throw new IllegalArgumentException("Rating cannot be null or empty");
        }

        try {
            LOGGER.info("Performing conditional update on MRSC global table: " + tableName);

            Map<String, AttributeValue> key = new HashMap<>();
            key.put("Artist", AttributeValue.builder().s(artist).build());
            key.put("SongTitle", AttributeValue.builder().s(songTitle).build());

            Map<String, String> expressionAttributeNames = new HashMap<>();
            expressionAttributeNames.put("#rating", "Rating");

            Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
            expressionAttributeValues.put(
                ":rating", AttributeValue.builder().n(rating).build());

            UpdateItemRequest updateItemRequest = UpdateItemRequest.builder()
                .tableName(tableName)
                .key(key)
                .updateExpression("SET #rating = :rating")
                .conditionExpression("attribute_exists(Artist)")
                .expressionAttributeNames(expressionAttributeNames)
                .expressionAttributeValues(expressionAttributeValues)
                .build();

            UpdateItemResponse response = dynamoDbClient.updateItem(updateItemRequest);
            LOGGER.info("Conditional update successful - demonstrates strong consistency");

            return response;

        } catch (ConditionalCheckFailedException e) {
            LOGGER.warning("Conditional check failed: " + e.getMessage());
            throw e;
        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to perform conditional update: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to perform conditional update: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Tunggu replika dan saksi MRSC menjadi aktif menggunakan. AWS SDK for Java 2.x  

```
    public static void waitForMRSCReplicasActive(
        final DynamoDbClient dynamoDbClient, final String tableName, final int maxWaitTimeSeconds)
        throws InterruptedException {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (maxWaitTimeSeconds <= 0) {
            throw new IllegalArgumentException("Max wait time must be positive");
        }

        try {
            LOGGER.info("Waiting for MRSC replicas and witnesses to become active: " + tableName);

            final long startTime = System.currentTimeMillis();
            final long maxWaitTimeMillis = maxWaitTimeSeconds * 1000L;
            int backoffSeconds = 5; // Start with 5 second intervals
            final int maxBackoffSeconds = 30; // Cap at 30 seconds

            while (System.currentTimeMillis() - startTime < maxWaitTimeMillis) {
                DescribeTableResponse response = describeMRSCTable(dynamoDbClient, tableName);

                boolean allActive = true;
                StringBuilder statusReport = new StringBuilder();

                if (response.table().multiRegionConsistency() == null
                    || !MultiRegionConsistency.STRONG
                        .toString()
                        .equals(response.table().multiRegionConsistency().toString())) {
                    allActive = false;
                    statusReport
                        .append("MultiRegionConsistency: ")
                        .append(response.table().multiRegionConsistency())
                        .append(" ");
                }
                if (response.table().replicas() == null
                    || response.table().replicas().isEmpty()) {
                    allActive = false;
                    statusReport.append("No replicas found. ");
                }
                if (response.table().globalTableWitnesses() == null
                    || response.table().globalTableWitnesses().isEmpty()) {
                    allActive = false;
                    statusReport.append("No witnesses found. ");
                }

                // Check table status
                if (!"ACTIVE".equals(response.table().tableStatus().toString())) {
                    allActive = false;
                    statusReport
                        .append("Table: ")
                        .append(response.table().tableStatus())
                        .append(" ");
                }

                // Check replica status
                if (response.table().replicas() != null) {
                    for (var replica : response.table().replicas()) {
                        if (!"ACTIVE".equals(replica.replicaStatus().toString())) {
                            allActive = false;
                            statusReport
                                .append("Replica(")
                                .append(replica.regionName())
                                .append("): ")
                                .append(replica.replicaStatus())
                                .append(" ");
                        }
                    }
                }

                // Check witness status
                if (response.table().globalTableWitnesses() != null) {
                    for (var witness : response.table().globalTableWitnesses()) {
                        if (!"ACTIVE".equals(witness.witnessStatus().toString())) {
                            allActive = false;
                            statusReport
                                .append("Witness(")
                                .append(witness.regionName())
                                .append("): ")
                                .append(witness.witnessStatus())
                                .append(" ");
                        }
                    }
                }

                if (allActive) {
                    LOGGER.info("All MRSC replicas and witnesses are now active: " + tableName);
                    return;
                }

                LOGGER.info("Waiting for MRSC components to become active. Status: " + statusReport.toString());
                LOGGER.info("Next check in " + backoffSeconds + " seconds...");

                tempWait(backoffSeconds);

                // Exponential backoff with cap
                backoffSeconds = Math.min(backoffSeconds * 2, maxBackoffSeconds);
            }

            throw DynamoDbException.builder()
                .message("Timeout waiting for MRSC replicas to become active after " + maxWaitTimeSeconds + " seconds")
                .build();

        } catch (DynamoDbException | InterruptedException e) {
            LOGGER.severe("Failed to wait for MRSC replicas to become active: " + tableName + " - " + e.getMessage());
            throw e;
        }
    }
```
Bersihkan replika dan saksi MRSC menggunakan. AWS SDK for Java 2.x  

```
    public static UpdateTableResponse cleanupMRSCReplicas(
        final DynamoDbClient dynamoDbClient,
        final String tableName,
        final Region replicaRegion,
        final Region witnessRegion) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (replicaRegion == null) {
            throw new IllegalArgumentException("Replica region cannot be null");
        }
        if (witnessRegion == null) {
            throw new IllegalArgumentException("Witness region cannot be null");
        }

        try {
            LOGGER.info("Cleaning up MRSC replicas and witnesses for table: " + tableName);

            // Remove replica using ReplicationGroupUpdate
            ReplicationGroupUpdate replicaUpdate = ReplicationGroupUpdate.builder()
                .delete(DeleteReplicationGroupMemberAction.builder()
                    .regionName(replicaRegion.id())
                    .build())
                .build();

            // Remove witness
            GlobalTableWitnessGroupUpdate witnessUpdate = GlobalTableWitnessGroupUpdate.builder()
                .delete(DeleteGlobalTableWitnessGroupMemberAction.builder()
                    .regionName(witnessRegion.id())
                    .build())
                .build();

            UpdateTableRequest updateTableRequest = UpdateTableRequest.builder()
                .tableName(tableName)
                .replicaUpdates(List.of(replicaUpdate))
                .globalTableWitnessUpdates(List.of(witnessUpdate))
                .build();

            UpdateTableResponse response = dynamoDbClient.updateTable(updateTableRequest);
            LOGGER.info("MRSC cleanup initiated - removing replica and witness. Response: " + response);

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to cleanup MRSC replicas: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to cleanup MRSC replicas: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Demonstrasi alur kerja MRSC lengkap menggunakan. AWS SDK for Java 2.x  

```
    public static void demonstrateCompleteMRSCWorkflow(
        final DynamoDbClient primaryClient,
        final DynamoDbClient replicaClient,
        final String tableName,
        final Region replicaRegion,
        final Region witnessRegion)
        throws InterruptedException {

        if (primaryClient == null) {
            throw new IllegalArgumentException("Primary DynamoDB client cannot be null");
        }
        if (replicaClient == null) {
            throw new IllegalArgumentException("Replica DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (replicaRegion == null) {
            throw new IllegalArgumentException("Replica region cannot be null");
        }
        if (witnessRegion == null) {
            throw new IllegalArgumentException("Witness region cannot be null");
        }

        try {
            LOGGER.info("=== Starting Complete MRSC Workflow Demonstration ===");

            // Step 1: Create an empty single-Region table
            LOGGER.info("Step 1: Creating empty single-Region table");
            createRegionalTable(primaryClient, tableName);

            // Use the existing GlobalTableOperations method for basic table waiting
            LOGGER.info("Intermediate step: Waiting for table [" + tableName + "] to become active before continuing");
            GlobalTableOperations.waitForTableActive(primaryClient, tableName);

            // Step 2: Convert to MRSC with replica and witness
            LOGGER.info("Step 2: Converting to MRSC with replica and witness");
            convertToMRSCWithWitness(primaryClient, tableName, replicaRegion, witnessRegion);

            // Wait for MRSC conversion to complete using MRSC-specific waiter
            LOGGER.info("Waiting for MRSC conversion to complete...");
            waitForMRSCReplicasActive(primaryClient, tableName);

            LOGGER.info("Intermediate step: Waiting for table [" + tableName + "] to become active before continuing");
            GlobalTableOperations.waitForTableActive(primaryClient, tableName);

            // Step 3: Verify MRSC configuration
            LOGGER.info("Step 3: Verifying MRSC configuration");
            describeMRSCTable(primaryClient, tableName);

            // Step 4: Test strong consistency with data operations
            LOGGER.info("Step 4: Testing strong consistency with data operations");

            // Add test item to primary region
            putTestItem(primaryClient, tableName, "The Beatles", "Hey Jude", "The Beatles 1967-1970", "1968");

            // Immediately read from replica region (no wait needed with MRSC)
            LOGGER.info("Reading from replica region immediately (strong consistency):");
            GetItemResponse getResponse =
                getItemWithConsistentRead(replicaClient, tableName, "The Beatles", "Hey Jude");

            if (getResponse.hasItem()) {
                LOGGER.info("✓ Strong consistency verified - item immediately available in replica region");
            } else {
                LOGGER.warning("✗ Item not found in replica region");
            }

            // Test conditional update from replica region
            LOGGER.info("Testing conditional update from replica region:");
            performConditionalUpdate(replicaClient, tableName, "The Beatles", "Hey Jude", "5");
            LOGGER.info("✓ Conditional update successful - demonstrates strong consistency");

            // Step 5: Cleanup
            LOGGER.info("Step 5: Cleaning up resources");
            cleanupMRSCReplicas(primaryClient, tableName, replicaRegion, witnessRegion);

            // Wait for cleanup to complete using basic table waiter
            LOGGER.info("Waiting for replica cleanup to complete...");
            GlobalTableOperations.waitForTableActive(primaryClient, tableName);

            // "Halt" until replica/witness cleanup is complete
            DescribeTableResponse cleanupVerification = describeMRSCTable(primaryClient, tableName);
            int backoffSeconds = 5; // Start with 5 second intervals
            while (cleanupVerification.table().multiRegionConsistency() != null) {
                LOGGER.info("Waiting additional time (" + backoffSeconds + " seconds) for MRSC cleanup to complete...");
                tempWait(backoffSeconds);

                // Exponential backoff with cap
                backoffSeconds = Math.min(backoffSeconds * 2, 30);
                cleanupVerification = describeMRSCTable(primaryClient, tableName);
            }

            // Delete the primary table
            deleteTable(primaryClient, tableName);

            LOGGER.info("=== MRSC Workflow Demonstration Complete ===");
            LOGGER.info("");
            LOGGER.info("Key benefits of Multi-Region Strong Consistency (MRSC):");
            LOGGER.info("- Immediate consistency across all regions (no eventual consistency delays)");
            LOGGER.info("- Simplified application logic (no need to handle eventual consistency)");
            LOGGER.info("- Support for conditional writes and transactions across regions");
            LOGGER.info("- Consistent read operations from any region without waiting");

        } catch (DynamoDbException | InterruptedException e) {
            LOGGER.severe("MRSC workflow failed: " + e.getMessage());
            throw e;
        }
    }
```
+ Untuk detail API, lihat topik berikut di *Referensi API AWS SDK for Java 2.x *.
  + [CreateTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/CreateTable)
  + [DeleteTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/DeleteTable)
  + [DescribeTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/DescribeTable)
  + [GetItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/GetItem)
  + [PutItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/PutItem)
  + [UpdateItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem)
  + [UpdateTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateTable)

------

# DynamoDB tabel global keamanan
<a name="globaltables-security"></a>

Replika tabel global adalah tabel DynamoDB, sehingga Anda menggunakan metode yang sama untuk mengontrol akses ke replika yang Anda lakukan untuk tabel wilayah tunggal, AWS Identity and Access Management termasuk kebijakan identitas (IAM) dan kebijakan berbasis sumber daya.

Topik ini mencakup cara mengamankan tabel global DynamoDB menggunakan izin AWS Key Management Service IAM dan enkripsi ().AWS KMS Anda mempelajari tentang peran terkait layanan (SLR) yang memungkinkan replikasi lintas wilayah dan auto-scaling, izin IAM yang diperlukan untuk membuat, memperbarui, dan menghapus tabel global, dan perbedaan antara tabel konsistensi akhir Multi-wilayah (MREC) dan Multi-region strong consistency (MRSC). Anda juga mempelajari kunci AWS KMS enkripsi untuk mengelola replikasi lintas wilayah dengan aman.

## Peran terkait layanan untuk tabel global
<a name="globaltables-slr"></a>

Tabel global DynamoDB mengandalkan peran terkait layanan SLRs () untuk mengelola replikasi lintas wilayah dan kemampuan auto-scaling.

Anda hanya perlu mengatur peran ini sekali per AWS akun. Setelah dibuat, peran yang sama melayani semua tabel global di akun Anda. Untuk informasi selengkapnya tentang peran tertaut layanan, lihat [Menggunakan peran tertaut layanan](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html) di *Panduan Pengguna IAM*.

### Peran terkait layanan replikasi
<a name="globaltables-replication-slr"></a>

Amazon DynamoDB secara otomatis membuat `AWSServiceRoleForDynamoDBReplication` peran terkait layanan (SLR) saat Anda membuat tabel global pertama Anda. Peran ini mengelola replikasi lintas wilayah untuk Anda.

Saat menerapkan kebijakan berbasis sumber daya ke replika, pastikan Anda tidak menolak izin apa pun yang ditentukan dalam prinsip `AWSServiceRoleForDynamoDBReplicationPolicy` ke SLR, karena ini akan mengganggu replikasi. Jika Anda menolak izin SLR yang diperlukan, replikasi ke dan dari replika yang terpengaruh akan berhenti, dan status tabel replika akan berubah menjadi. `REPLICATION_NOT_AUTHORIZED`
+ Untuk tabel global Multi-region eventual consistency (MREC), jika replika tetap dalam `REPLICATION_NOT_AUTHORIZED` status selama lebih dari 20 jam, replika dikonversi secara ireversibel ke tabel DynamoDB wilayah Tunggal.
+ Untuk tabel global Multi-region strong consistency (MRSC), penolakan izin yang diperlukan menghasilkan operasi penulisan dan `AccessDeniedException` pembacaan yang sangat konsisten. Jika replika tetap dalam `REPLICATION_NOT_AUTHORIZED` status selama lebih dari tujuh hari, replika menjadi tidak dapat diakses secara permanen, dan operasi tulis dan baca yang sangat konsisten akan terus gagal dengan kesalahan. Beberapa operasi manajemen seperti penghapusan replika akan berhasil.

### Peran terkait layanan penskalaan otomatis
<a name="globaltables-autoscaling-slr"></a>

Saat mengonfigurasi tabel global untuk mode kapasitas yang disediakan, penskalaan otomatis harus dikonfigurasi untuk tabel global. DynamoDB auto scaling menggunakan layanan Application AWS Auto Scaling untuk secara dinamis menyesuaikan kapasitas throughput yang disediakan pada replika tabel global Anda. Layanan Application Auto Scaling membuat peran terkait layanan (SLR) bernama. [https://docs.aws.amazon.com/autoscaling/application/userguide/application-auto-scaling-service-linked-roles.html](https://docs.aws.amazon.com/autoscaling/application/userguide/application-auto-scaling-service-linked-roles.html) Peran terkait layanan ini secara otomatis dibuat di AWS akun Anda saat pertama kali mengonfigurasi penskalaan otomatis untuk tabel DynamoDB. Ini memungkinkan Application Auto Scaling untuk mengelola kapasitas tabel yang disediakan dan membuat alarm. CloudWatch 

 Saat menerapkan kebijakan berbasis sumber daya ke replika, pastikan Anda tidak menolak izin apa pun yang ditentukan dalam prinsip Application [https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSApplicationAutoscalingDynamoDBTablePolicy.html](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSApplicationAutoscalingDynamoDBTablePolicy.html)Auto Scaling SLR, karena ini akan mengganggu fungsionalitas penskalaan otomatis.

### Contoh kebijakan IAM untuk peran terkait layanan
<a name="globaltables-example-slr"></a>

Kebijakan IAM dengan kondisi berikut tidak memengaruhi izin yang diperlukan ke SLR replikasi DynamoDB dan SLR Auto Scaling. AWS Kondisi ini dapat ditambahkan ke kebijakan yang membatasi secara luas untuk menghindari gangguan replikasi atau penskalaan otomatis secara tidak sengaja.

#### Tidak termasuk izin SLR yang diperlukan dari kebijakan penolakan
<a name="example-exclude-slr-policy"></a>

Contoh berikut menunjukkan cara mengecualikan prinsipal peran terkait layanan dari pernyataan penolakan:

```
"Condition": {
    "StringNotEquals": {
        "aws:PrincipalArn": [
            "arn:aws::iam::111122223333:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication",
            "arn:aws::iam::111122223333:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable"
        ]
    }
}
```

## Bagaimana tabel global menggunakan AWS IAM
<a name="globaltables-iam"></a>

Bagian berikut menjelaskan izin yang diperlukan untuk operasi tabel global yang berbeda dan memberikan contoh kebijakan untuk membantu Anda mengonfigurasi akses yang sesuai untuk pengguna dan aplikasi Anda.

**catatan**  
Semua izin yang dijelaskan harus diterapkan ke ARN sumber daya tabel tertentu di Wilayah yang terpengaruh. Sumber daya tabel ARN mengikuti format`arn:aws:dynamodb:region:account-id:table/table-name`, di mana Anda perlu menentukan nilai Region, ID akun, dan nama tabel yang sebenarnya.

**Topics**
+ [Membuat tabel global dan menambahkan replika](#globaltables-creation-iam)
+ [Memperbarui tabel global](#globaltables-update-iam)
+ [Menghapus tabel global dan menghapus replika](#globaltables-delete-iam)

### Membuat tabel global dan menambahkan replika
<a name="globaltables-creation-iam"></a>

Tabel global DynamoDB mendukung dua mode konsistensi: Multi-region endal consistency (MREC) dan Multi-region strong consistency (MRSC). Tabel global MREC dapat memiliki beberapa replika di sejumlah Wilayah dan memberikan konsistensi akhirnya. Tabel global MRSC membutuhkan tepat tiga Wilayah (tiga replika atau dua replika dan satu saksi) dan memberikan konsistensi yang kuat dengan tujuan titik pemulihan nol (RPO).

Izin yang diperlukan untuk membuat tabel global bergantung pada apakah Anda membuat tabel global dengan atau tanpa saksi.

#### Izin untuk membuat tabel global
<a name="globaltables-creation-iam-all-types"></a>

Izin berikut diperlukan baik untuk pembuatan tabel global awal dan untuk menambahkan replika nanti. Izin ini berlaku untuk tabel global Konsistensi Akhir Multi-Wilayah (MREC) dan Multi-Region Strong Consistency (MRSC).
+ Tabel global memerlukan replikasi lintas wilayah, yang dikelola DynamoDB melalui peran terkait layanan (SLR). [`AWSServiceRoleForDynamoDBReplication`](#globaltables-replication-slr) Izin berikut memungkinkan DynamoDB untuk membuat peran ini secara otomatis saat Anda membuat tabel global untuk pertama kalinya:
  + `iam:CreateServiceLinkedRole`
+ Untuk membuat tabel global atau menambahkan replika menggunakan [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html)API, Anda harus memiliki izin berikut pada sumber daya tabel sumber:
  + `dynamodb:UpdateTable`
+ Anda harus memiliki izin berikut pada sumber daya tabel di Wilayah untuk replika yang akan ditambahkan:
  + `dynamodb:CreateTable`
  + `dynamodb:CreateTableReplica`
  + `dynamodb:Query`
  + `dynamodb:Scan`
  + `dynamodb:UpdateItem`
  + `dynamodb:PutItem`
  + `dynamodb:GetItem`
  + `dynamodb:DeleteItem`
  + `dynamodb:BatchWriteItem`

#### Izin tambahan untuk tabel global MRSC menggunakan saksi
<a name="globaltables-creation-iam-witness"></a>

Saat membuat tabel global Konsistensi Kuat Multi-Wilayah (MRSC) dengan Wilayah saksi, Anda harus memiliki izin berikut pada sumber daya tabel di semua Wilayah yang berpartisipasi (termasuk Wilayah replika dan Wilayah saksi):
+ `dynamodb:CreateGlobalTableWitness`

#### Contoh kebijakan IAM untuk membuat tabel global
<a name="globaltables-creation-iam-example"></a>

##### Membuat tabel global MREC atau MRSC di tiga Wilayah
<a name="globaltables-creation-iam-example-three-regions"></a>

Kebijakan berbasis identitas berikut memungkinkan Anda membuat tabel global MREC atau MRSC bernama “pengguna” di tiga Wilayah, termasuk membuat peran terkait layanan replikasi DynamoDB yang diperlukan.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowCreatingUsersGlobalTable",
      "Effect": "Allow",
      "Action": [
        "dynamodb:CreateTable",
        "dynamodb:CreateTableReplica",
        "dynamodb:UpdateTable",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem",
        "dynamodb:PutItem",
        "dynamodb:GetItem",
        "dynamodb:DeleteItem",
        "dynamodb:BatchWriteItem"
      ],
      "Resource": [
        "arn:aws:dynamodb:us-east-1:123456789012:table/users",
        "arn:aws:dynamodb:us-east-2:123456789012:table/users",
        "arn:aws:dynamodb:us-west-2:123456789012:table/users"
      ]
    },
    {
      "Sid": "AllowCreatingSLR",
      "Effect": "Allow",
      "Action": [
        "iam:CreateServiceLinkedRole"
      ],
      "Resource": [
        "arn:aws:iam::123456789012:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication"
      ]
    }
  ]
}
```

------

##### Membatasi pembuatan tabel global MREC atau MRSC ke Wilayah tertentu
<a name="globaltables-creation-iam-example-restrict-regions"></a>

Kebijakan berbasis identitas berikut memungkinkan Anda membuat replika tabel global DynamoDB di seluruh Wilayah tertentu menggunakan RequestedRegion kunci kondisi [aws:](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-requestedregion), termasuk membuat peran terkait layanan replikasi DynamoDB yang diperlukan.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowAddingReplicasToSourceTable",
      "Effect": "Allow",
      "Action": [
        "dynamodb:UpdateTable"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": [
            "us-east-1"
          ]
        }
      }
    },
    {
      "Sid": "AllowCreatingReplicas",
      "Effect": "Allow",
      "Action": [
        "dynamodb:CreateTable",
        "dynamodb:CreateTableReplica",
        "dynamodb:UpdateTable",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem",
        "dynamodb:PutItem",
        "dynamodb:GetItem",
        "dynamodb:DeleteItem",
        "dynamodb:BatchWriteItem"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": [
            "us-east-2",
            "us-west-2"
          ]
        }
      }
    },
    {
      "Sid": "AllowCreatingSLR",
      "Effect": "Allow",
      "Action": [
        "iam:CreateServiceLinkedRole"
      ],
      "Resource": [
        "arn:aws:iam::123456789012:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication"
      ]
    }
  ]
}
```

------

##### Membuat tabel global MRSC dengan saksi
<a name="globaltables-creation-iam-example-witness"></a>

Kebijakan berbasis identitas berikut memungkinkan Anda membuat tabel global DynamoDB MRSC bernama “users” dengan replika di us-east-1 dan us-east-2 dan saksi di us-west-2, termasuk membuat peran terkait layanan replikasi DynamoDB yang diperlukan.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowCreatingUsersGlobalTableWithWitness",
      "Effect": "Allow",
      "Action": [
        "dynamodb:CreateTable",
        "dynamodb:CreateTableReplica",
        "dynamodb:CreateGlobalTableWitness",
        "dynamodb:UpdateTable",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem",
        "dynamodb:PutItem",
        "dynamodb:GetItem",
        "dynamodb:DeleteItem",
        "dynamodb:BatchWriteItem"
      ],
      "Resource": [
        "arn:aws:dynamodb:us-east-1:123456789012:table/users",
        "arn:aws:dynamodb:us-east-2:123456789012:table/users"
      ]
    },
    {
      "Sid": "AllowCreatingSLR",
      "Effect": "Allow",
      "Action": [
        "iam:CreateServiceLinkedRole"
      ],
      "Resource": [
        "arn:aws:iam::123456789012:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication"
      ]
    }
  ]
}
```

------

##### Membatasi penciptaan saksi MRSC ke Wilayah tertentu
<a name="globaltables-creation-iam-example-restrict-witness-regions"></a>

Kebijakan berbasis identitas ini memungkinkan Anda membuat tabel global MRSC dengan replika yang dibatasi untuk Wilayah tertentu menggunakan kunci RequestedRegion kondisi [aws:](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-requestedregion) dan pembuatan saksi tak terbatas di semua Wilayah, termasuk membuat peran terkait layanan replikasi DynamoDB yang diperlukan.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowCreatingReplicas",
      "Effect": "Allow",
      "Action": [
        "dynamodb:CreateTable",
        "dynamodb:CreateTableReplica",
        "dynamodb:UpdateTable",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem",
        "dynamodb:PutItem",
        "dynamodb:GetItem",
        "dynamodb:DeleteItem",
        "dynamodb:BatchWriteItem"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": [
            "us-east-1",
            "us-east-2"
          ]
        }
      }
    },
    {
      "Sid": "AllowCreatingWitness",
      "Effect": "Allow",
      "Action": [
        "dynamodb:CreateGlobalTableWitness"
      ],
      "Resource": "*"
    },
    {
      "Sid": "AllowCreatingSLR",
      "Effect": "Allow",
      "Action": [
        "iam:CreateServiceLinkedRole"
      ],
      "Resource": [
        "arn:aws:iam::123456789012:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication"
      ]
    }
  ]
}
```

------

### Memperbarui tabel global
<a name="globaltables-update-iam"></a>

Untuk mengubah setelan replika untuk tabel global yang ada menggunakan [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html)API, Anda memerlukan izin berikut pada sumber daya tabel di Wilayah tempat Anda melakukan panggilan API:
+ `dynamodb:UpdateTable`

Anda juga dapat memperbarui konfigurasi tabel global lainnya, seperti kebijakan penskalaan otomatis dan pengaturan Time to Live. Izin berikut diperlukan untuk operasi pembaruan tambahan ini:
+ Untuk memperbarui kebijakan penskalaan otomatis replika dengan [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTableReplicaAutoScaling.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTableReplicaAutoScaling.html)API, Anda harus memiliki izin berikut pada sumber daya tabel di semua Wilayah yang berisi replika:
  + `application-autoscaling:DeleteScalingPolicy`
  + `application-autoscaling:DeleteScheduledAction`
  + `application-autoscaling:DeregisterScalableTarget`
  + `application-autoscaling:DescribeScalableTargets`
  + `application-autoscaling:DescribeScalingActivities`
  + `application-autoscaling:DescribeScalingPolicies`
  + `application-autoscaling:DescribeScheduledActions`
  + `application-autoscaling:PutScalingPolicy`
  + `application-autoscaling:PutScheduledAction`
  + `application-autoscaling:RegisterScalableTarget`
+ Untuk memperbarui pengaturan Waktu ke Langsung dengan [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTimeToLive.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTimeToLive.html)API, Anda harus memiliki izin berikut pada sumber daya tabel di semua Wilayah yang berisi replika:
  + `dynamodb:UpdateTimeToLive`

  Perhatikan bahwa Time to Live (TTL) hanya didukung untuk tabel global yang dikonfigurasi dengan Multi-Region Eventual Consistency (MREC). Untuk informasi selengkapnya tentang cara kerja tabel global dengan TTL, lihat [Cara kerja tabel global DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/V2globaltables_HowItWorks.html).

### Menghapus tabel global dan menghapus replika
<a name="globaltables-delete-iam"></a>

Untuk menghapus tabel global, Anda harus menghapus semua replika. Izin yang diperlukan untuk operasi ini berbeda tergantung pada apakah Anda menghapus tabel global dengan atau tanpa Wilayah saksi.

#### Izin untuk menghapus tabel global dan menghapus replika
<a name="globaltables-delete-iam-all-types"></a>

Izin berikut diperlukan baik untuk menghapus replika individual dan untuk menghapus tabel global sepenuhnya. Menghapus konfigurasi tabel global hanya menghapus hubungan replikasi antara tabel di Wilayah yang berbeda. Itu tidak menghapus tabel DynamoDB yang mendasari di Wilayah terakhir yang tersisa. Tabel di Wilayah terakhir terus ada sebagai tabel DynamoDB standar dengan data dan pengaturan yang sama. Izin ini berlaku untuk tabel global Konsistensi Akhir Multi-Wilayah (MREC) dan Multi-Region Strong Consistency (MRSC). 
+ Untuk menghapus replika dari tabel global menggunakan [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html)API, Anda memerlukan izin berikut pada sumber daya tabel di Wilayah tempat Anda melakukan panggilan API:
  + `dynamodb:UpdateTable`
+ Anda memerlukan izin berikut pada sumber daya tabel di setiap Wilayah tempat Anda menghapus replika:
  + `dynamodb:DeleteTable`
  + `dynamodb:DeleteTableReplica`

#### Izin tambahan untuk tabel global MRSC menggunakan saksi
<a name="globaltables-delete-iam-witness"></a>

Untuk menghapus tabel global Multi-region strong consistency (MRSC) dengan saksi, Anda harus memiliki izin berikut pada sumber daya tabel di semua Wilayah yang berpartisipasi (termasuk Wilayah replika dan Wilayah saksi):
+ `dynamodb:DeleteGlobalTableWitness`

#### Contoh kebijakan IAM untuk menghapus replika tabel global
<a name="globaltables-delete-iam-example"></a>

##### Menghapus replika tabel global
<a name="globaltables-delete-replicas-iam-example"></a>

Kebijakan berbasis identitas ini memungkinkan Anda menghapus tabel global DynamoDB bernama “pengguna” dan replika di tiga Wilayah:

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:UpdateTable",
        "dynamodb:DeleteTable",
        "dynamodb:DeleteTableReplica"
      ],
      "Resource": [
        "arn:aws:dynamodb:us-east-1:123456789012:table/users",
        "arn:aws:dynamodb:us-east-2:123456789012:table/users",
        "arn:aws:dynamodb:us-west-2:123456789012:table/users"
      ]
    }
  ]
}
```

------

##### Menghapus tabel global MRSC dengan saksi
<a name="globaltables-delete-witness-iam-example"></a>

Kebijakan berbasis identitas ini memungkinkan Anda untuk menghapus replika dan saksi tabel global MRSC bernama “pengguna”:

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:UpdateTable",
        "dynamodb:DeleteTable",
        "dynamodb:DeleteTableReplica",
        "dynamodb:DeleteGlobalTableWitness"
      ],
      "Resource": [
        "arn:aws:dynamodb:us-east-1:123456789012:table/users",
        "arn:aws:dynamodb:us-east-2:123456789012:table/users"
      ]
    }
  ]
}
```

------

## Bagaimana tabel global menggunakan AWS KMS
<a name="globaltables-kms"></a>

Seperti semua tabel DynamoDB, replika tabel global selalu mengenkripsi data saat istirahat menggunakan kunci enkripsi yang disimpan AWS di Key Management Service ().AWS KMS

Semua replika dalam tabel global harus dikonfigurasi dengan jenis kunci KMS yang sama (kunci AWS milik, kunci AWS terkelola, atau kunci yang dikelola Pelanggan).

**penting**  
DynamoDB memerlukan akses ke kunci enkripsi replika untuk menghapus replika. Jika Anda ingin menonaktifkan atau menghapus kunci terkelola pelanggan yang digunakan untuk mengenkripsi replika karena Anda menghapus replika, Anda harus terlebih dahulu menghapus replika, menunggu status tabel pada salah satu replika yang tersisa untuk berubah`ACTIVE`, lalu menonaktifkan atau menghapus kunci.

Untuk tabel global yang dikonfigurasi untuk konsistensi akhir Multi-wilayah (MREC), jika Anda menonaktifkan atau mencabut akses DynamoDB ke kunci terkelola pelanggan yang digunakan untuk mengenkripsi replika, replikasi ke dan dari replika akan berhenti dan status replika akan berubah menjadi. `INACCESSIBLE_ENCRYPTION_CREDENTIALS` Jika replika dalam tabel global MREC tetap dalam `INACCESSIBLE_ENCRYPTION_CREDENTIALS` status selama lebih dari 20 jam, replika dikonversi secara ireversibel ke tabel DynamoDB wilayah Tunggal.

Untuk tabel global yang dikonfigurasi untuk konsistensi kuat Multi-wilayah (MRSC), jika Anda menonaktifkan atau mencabut akses DynamoDB ke kunci terkelola pelanggan yang digunakan untuk mengenkripsi replika, replikasi ke dan dari replika akan berhenti, upaya untuk melakukan penulisan atau pembacaan yang sangat konsisten ke replika akan mengembalikan kesalahan, dan status replika akan berubah menjadi. `INACCESSIBLE_ENCRYPTION_CREDENTIALS` Jika replika dalam tabel global MRSC tetap dalam `INACCESSIBLE_ENCRYPTION_CREDENTIALS` status selama lebih dari tujuh hari, tergantung pada izin tertentu yang dicabut, replika akan diarsipkan atau menjadi tidak dapat diakses secara permanen.

# Tabel global multi-akun DynamoDB
<a name="globaltables-MultiAccount"></a>

Tabel global multi-akun secara otomatis mereplikasi data tabel DynamoDB Anda di beberapa AWS Wilayah dan beberapa AWS akun untuk meningkatkan ketahanan, mengisolasi beban kerja di tingkat akun, dan menerapkan kontrol keamanan dan tata kelola yang berbeda. Setiap tabel replika berada di AWS akun yang berbeda, memungkinkan isolasi kesalahan di tingkat Wilayah dan akun. Anda juga dapat menyelaraskan replika dengan AWS struktur organisasi Anda. Tabel global multi-akun memberikan manfaat isolasi, tata kelola, dan keamanan tambahan dibandingkan dengan tabel global akun yang sama.

Tabel global multi-akun memberikan manfaat berikut:
+ Replikasi data tabel DynamoDB secara otomatis di seluruh akun dan Wilayah pilihan Anda AWS 
+ Meningkatkan keamanan dan tata kelola dengan mereplikasi data di seluruh akun dengan kebijakan, pagar pembatas, dan batasan kepatuhan yang berbeda
+ Meningkatkan ketahanan operasional dan isolasi kesalahan tingkat akun dengan menempatkan replika di akun terpisah AWS 
+ Sejajarkan beban kerja berdasarkan unit bisnis atau kepemilikan saat menggunakan strategi multi-akun
+ Sederhanakan atribusi biaya dengan menagih setiap replika ke akun masing-masing AWS 

Untuk informasi selengkapnya, lihat [Manfaat menggunakan beberapa AWS akun](https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/benefits-of-using-multiple-aws-accounts.html). Jika beban kerja Anda tidak memerlukan replikasi multi-akun, atau Anda ingin pengelolaan replika yang lebih sederhana dengan penggantian lokal, Anda dapat terus menggunakan tabel global akun yang sama.

Anda dapat mengonfigurasi tabel global multi-akun dengan[Konsistensi akhir Multi-Region (MREC)](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes.mrec). Tabel global yang dikonfigurasi untuk [Konsistensi kuat Multi-Region (MRSC)](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes.mrsc) tidak mendukung model multi-akun.

**Topics**
+ [Cara kerja tabel global DynamoDB](V2globaltables_MA_HowItWorks.md)
+ [Tutorial: Membuat tabel global multi-akun](V2globaltables_MA.tutorial.md)
+ [DynamoDB tabel global keamanan](globaltables_MA_security.md)

# Cara kerja tabel global DynamoDB
<a name="V2globaltables_MA_HowItWorks"></a>

Tabel global multi-akun memperluas tabel global DynamoDB yang dikelola sepenuhnya, tanpa server, Multi-wilayah, dan kemampuan multi-aktif untuk menjangkau beberapa akun. AWS Tabel global multi-akun mereplikasi data di seluruh AWS Wilayah dan akun, menyediakan fungsionalitas aktif-aktif yang sama dengan tabel global akun yang sama. Saat Anda menulis ke replika apa pun, DynamoDB mereplikasi data ke semua replika lainnya.

Perbedaan utama dari tabel global akun yang sama meliputi:
+ Replikasi multi-akun didukung untuk tabel global Multi-region eventual consistency (MREC).
+ Anda hanya dapat menambahkan replika dengan memulai dengan tabel Single-region. Mengonversi tabel global akun yang sama yang ada menjadi pengaturan multi-akun tidak didukung. Untuk bermigrasi, Anda harus menghapus replika yang ada untuk kembali ke tabel Single-region sebelum membuat tabel global multi-akun baru.
+ Setiap replika harus berada di akun terpisah AWS . Untuk tabel global multi-akun dengan replika *N*, Anda harus memiliki akun *N*.
+ Tabel global multi-akun menggunakan pengaturan tabel terpadu di semua replika secara default. Semua replika secara otomatis berbagi konfigurasi yang sama (seperti mode throughput dan TTL), dan tidak seperti tabel global akun yang sama, pengaturan ini tidak dapat diganti per replika.
+ Pelanggan harus memberikan izin replikasi ke prinsipal layanan tabel global DynamoDB dalam kebijakan sumber daya mereka.

Tabel global multi-akun menggunakan teknologi replikasi dasar yang sama dengan tabel global akun yang sama. Pengaturan tabel direplikasi secara otomatis di semua replika regional, dan pelanggan tidak dapat mengganti atau menyesuaikan pengaturan per replika. Ini memastikan konfigurasi yang konsisten dan perilaku yang dapat diprediksi di beberapa AWS akun yang berpartisipasi dalam tabel global yang sama.

Pengaturan dalam tabel global DynamoDB menentukan bagaimana tabel berperilaku dan bagaimana data direplikasi di seluruh Wilayah. Pengaturan ini dikonfigurasi melalui APIs bidang kontrol DynamoDB selama pembuatan tabel atau saat menambahkan replika regional baru.

Saat membuat tabel global multi-akun, pelanggan harus mengatur `GlobalTableSettingsReplicationMode = ENABLED` untuk setiap replika regional. Ini memastikan bahwa perubahan konfigurasi yang dibuat di satu Wilayah menyebar secara otomatis ke semua Wilayah lain yang berpartisipasi dalam tabel global.

Anda dapat mengaktifkan replikasi pengaturan setelah pembuatan tabel. Ini mendukung skenario di mana tabel awalnya dibuat sebagai tabel regional dan kemudian ditingkatkan ke tabel global multi-akun.

**Pengaturan yang Disinkronkan**

Pengaturan tabel berikut selalu disinkronkan di semua replika dalam tabel global multi-akun:

**catatan**  
Tidak seperti tabel global akun yang sama, tabel global multi-akun tidak mengizinkan penggantian Per-wilayah untuk pengaturan ini. Satu-satunya pengecualian adalah penggantian untuk kebijakan auto-scaling baca (tabel dan GSIs) diizinkan karena merupakan sumber daya eksternal yang terpisah.
+ Mode kapasitas (kapasitas yang disediakan atau sesuai permintaan)
+ Tabel menyediakan kapasitas baca dan tulis
+ Tabel membaca dan menulis penskalaan otomatis
+ Definisi Indeks Sekunder Lokal (LSI)
+ Definisi Indeks Sekunder Global (GSI)
+ GSI menyediakan kapasitas baca dan tulis
+ GSI membaca dan menulis penskalaan otomatis
+ Definisi aliran dalam mode MREC
+ Waktu Untuk Tayang (TTL)
+ Throughput Hangat
+ Throughput baca dan tulis maksimum sesuai permintaan

**Pengaturan Non-Sinkronisasi**

Pengaturan berikut tidak disinkronkan antara replika dan harus dikonfigurasi secara independen untuk setiap tabel replika di setiap Wilayah.
+ Kelas Tabel
+ Jenis Enkripsi sisi server (SSE)
+ Point-in-time Pemulihan
+ Enkripsi sisi server (SSE) ID Kunci KMS
+ Perlindungan Penghapusan
+ Kinesis Data Streams (KDSD)
+ Tanda
+ Kebijakan Sumber Daya
+ Tabel Wawasan Kontributor Cloudwatch (CCI)
+ Wawasan Kontributor Cloudwatch GSI (CCI)

## Memantau
<a name="V2globaltables_MA_HowItWorks.monitoring"></a>

Tabel global yang dikonfigurasi untuk konsistensi akhir Multi-wilayah (MREC) mempublikasikan metrik ke. [`ReplicationLatency`](metrics-dimensions.md#ReplicationLatency) CloudWatch Metrik ini melacak waktu yang telah berlalu antara saat item ditulis ke tabel replika, dan kapan item itu muncul di replika lain di tabel global. `ReplicationLatency`dinyatakan dalam milidetik dan dipancarkan untuk setiap pasangan Wilayah sumber dan tujuan dalam tabel global.

`ReplicationLatency`Nilai tipikal tergantung pada jarak antara AWS Wilayah yang Anda pilih, serta variabel lain seperti jenis beban kerja dan throughput. Misalnya, replika sumber di Wilayah AS Barat (California Utara) (us-west-1) memiliki lebih rendah `ReplicationLatency` ke Wilayah Barat AS (Oregon) (us-west-2) dibandingkan dengan Wilayah Afrika (Cape Town) (af-south-1).

Nilai yang meningkat untuk `ReplicationLatency` dapat menunjukkan bahwa pembaruan dari satu replika tidak menyebar ke tabel replika lain secara tepat waktu. Dalam hal ini, Anda dapat mengalihkan sementara aktivitas baca dan tulis aplikasi Anda ke AWS Wilayah yang berbeda.

**Menangani Masalah Latensi Replikasi di Tabel Global Multi-akun**

Jika `ReplicationLatency` melebihi 3 jam karena masalah yang disebabkan oleh pelanggan pada tabel replika, DynamoDB mengirimkan pemberitahuan yang meminta pelanggan untuk mengatasi masalah mendasar. Masalah umum yang disebabkan oleh pelanggan yang dapat mencegah replikasi meliputi:
+ Menghapus izin yang diperlukan dari kebijakan sumber daya tabel replika
+ Memilih keluar dari AWS Wilayah yang menampung replika tabel global multi-akun
+ Menolak izin kunci AWS KMS tabel yang diperlukan untuk mendekripsi data

DynamoDB mengirimkan pemberitahuan awal dalam waktu 3 jam setelah latensi replikasi meningkat, diikuti dengan pemberitahuan kedua setelah 20 jam jika masalah tetap belum terselesaikan. Jika masalah tidak diperbaiki dalam jendela waktu yang diperlukan, DynamoDB akan secara otomatis memisahkan replika dari tabel global. Replika yang terpengaruh kemudian akan dikonversi ke tabel regional.

# Tutorial: Membuat tabel global multi-akun
<a name="V2globaltables_MA.tutorial"></a>

Bagian ini memberikan step-by-step petunjuk untuk membuat tabel global DynamoDB yang menjangkau beberapa akun. AWS 

## Buat tabel global multi-akun menggunakan konsol DynamoDB
<a name="create-ma-gt-console"></a>

Ikuti langkah-langkah ini untuk membuat tabel global multi-akun menggunakan. Konsol Manajemen AWS Contoh berikut membuat tabel global dengan tabel replika di Amerika Serikat.

1. Masuk ke Konsol Manajemen AWS dan buka konsol DynamoDB [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)di untuk akun pertama (katakanlah). *111122223333*

1. Untuk contoh ini, pilih **US East (Ohio)** dari pemilih Region di bilah navigasi.

1. Di panel navigasi di sisi kiri konsol, pilih **Tabel**.

1. Pilih **Buat Tabel**.

1. Pada halaman **Buat tabel**:

   1. Untuk **Nama tabel**, masukkan **MusicTable**.

   1. Untuk **kunci Partisi**, masukkan**Artist**.

   1. Untuk **tombol Sortir**, masukkan**SongTitle**.

   1. Simpan pengaturan default lainnya dan pilih **Buat tabel**.

1. Tambahkan kebijakan sumber daya berikut ke tabel

------
#### [ JSON ]

****  

   ```
   {
   "Version":"2012-10-17",		 	 	 
   "Statement": [
       {
           "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
           "Effect": "Allow",
           "Action": [
               "dynamodb:ReadDataForReplication",
               "dynamodb:WriteDataForReplication",
               "dynamodb:ReplicateSettings"
           ],
           "Resource": "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable",
           "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
           "Condition": {
               "StringEquals": {
                   "aws:SourceAccount": ["444455556666","111122223333"],
                   "aws:SourceArn": [
                       "arn:aws:dynamodb:us-east-1:444455556666:table/MusicTable",
                       "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable"
                   ]
               }
           }
       },
       {
           "Sid": "AllowTrustedAccountsToJoinThisGlobalTable",
           "Effect": "Allow",
           "Action": [
               "dynamodb:AssociateTableReplica"
           ],
           "Resource": "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable",
           "Principal": {"AWS": ["444455556666"]}
       }
   ]
   }
   ```

------

1. Tabel baru ini berfungsi sebagai tabel replika pertama dalam tabel global baru. Ini adalah protojenis untuk tabel replika lain yang Anda tambahkan nantinya.

1. Tunggu meja menjadi **Aktif**. Untuk tabel yang baru dibuat, dari tab **tabel Global**, navigasikan ke **Pengaturan Replikasi** dan klik **Aktifkan**.

1. Keluar dari akun ini (*111122223333*di sini).

1. Masuk ke Konsol Manajemen AWS dan buka konsol DynamoDB [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)di untuk akun kedua (katakanlah). *444455556666*

1. Untuk contoh ini, pilih **US East (Virginia N.)** dari pemilih Region di bilah navigasi.

1. Konsol memastikan bahwa tabel dengan nama yang sama tidak ada di Wilayah yang dipilih. Jika ada tabel dengan nama yang sama, Anda harus menghapus tabel yang ada sebelum dapat membuat tabel replika baru di Wilayah tersebut.

1. Di drop-down dekat **Create Table**, pilih **Create from other account**

1. Pada **tabel Buat dari halaman akun lain**:

   1. Tambahkan **arn:aws:dynamodb:us-east-2:*111122223333*:table/MusicTable** sebagai tabel arn untuk tabel sumber.

   1. Dalam **Tabel Replika ARNs**, tambahkan ARN dari tabel sumber lagi. **arn:aws:dynamodb:us-east-2:*111122223333*:table/MusicTable** Jika ada beberapa replika yang sudah ada sebagai bagian dari Tabel Global Multi Akun, Anda harus menambahkan setiap replika yang ada ke ReplicaTable ARN.

   1. Simpan pengaturan default lainnya dan pilih **Kirim**.

1. Tab **tabel Global** untuk tabel Musik (dan untuk tabel replika lainnya) menunjukkan bahwa tabel telah direplikasi di beberapa Wilayah.

1. Untuk menguji replikasi:

   1. Anda dapat menggunakan salah satu wilayah di mana replika ada untuk tabel ini

   1. Pilih **Jelajahi item tabel**.

   1. Pilih **Buat item**.

   1. Masuk **item\$11** untuk **Artis** dan **Song Value 1** untuk **SongTitle**.

   1. Pilih **Buat item**.

   1. Verifikasi replikasi dengan beralih ke wilayah lain:

   1. Verifikasi bahwa tabel Musik berisi item yang Anda buat.

## Buat tabel global multi-akun menggunakan AWS CLI
<a name="ma-gt-cli"></a>

Contoh berikut menunjukkan cara membuat tabel global multi-akun menggunakan. AWS CLI Contoh-contoh ini menunjukkan alur kerja lengkap untuk menyiapkan replikasi lintas akun.

------
#### [ CLI ]

Gunakan AWS CLI perintah berikut untuk membuat tabel global multi-akun dengan replikasi lintas akun.

```
# STEP 1: Setting resource policy for the table in account 111122223333

cat > /tmp/source-resource-policy.json << 'EOF'
{
    "Version": "2012-10-17", 		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": ["444455556666","111122223333"],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:us-east-1:444455556666:table/MusicTable",
                        "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable"
                    ]
                }
            }
        },
        {
            "Sid": "AllowTrustedAccountsToJoinThisGlobalTable",
            "Effect": "Allow",
            "Action": [
                "dynamodb:AssociateTableReplica"
            ],
            "Resource": "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable",
            "Principal": {"AWS": ["444455556666"]}
        }
    ]
}
EOF

# Step 2: Create a new table (MusicTable) in US East (Ohio), 
#   with DynamoDB Streams enabled (NEW_AND_OLD_IMAGES),
#   and Settings Replication ENABLED on the account 111122223333

aws dynamodb create-table \
    --table-name MusicTable \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --billing-mode PAY_PER_REQUEST \
    --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES \
    --global-table-settings-replication-mode ENABLED \
    --resource-policy file:///tmp/source-resource-policy.json \
    --region us-east-2 


# Step 3: Creating replica table in account 444455556666

# Resource policy for account 444455556666
cat > /tmp/dest-resource-policy.json << 'EOF'
{
    "Version": "2012-10-17", 		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:us-east-1:444455556666:table/MusicTable",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": ["444455556666","111122223333"],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:us-east-1:444455556666:table/MusicTable",
                        "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable"
                    ]
                }
            }
        }
    ]
}
EOF

# Execute the replica table creation
aws dynamodb create-table \
    --table-name MusicTable \
    --global-table-source-arn "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable" \
    --resource-policy file:///tmp/dest-resource-policy.json \
    --global-table-settings-replication-mode ENABLED \
    --region us-east-1

# Step 4: View the list of replicas created using describe-table
aws dynamodb describe-table \
    --table-name MusicTable \
    --region us-east-2 \
    --query 'Table.{TableName:TableName,TableStatus:TableStatus,MultiRegionConsistency:MultiRegionConsistency,Replicas:Replicas[*].{Region:RegionName,Status:ReplicaStatus}}'

# Step 5: To verify that replication is working, add a new item to the Music table in US East (Ohio)
aws dynamodb put-item \
    --table-name MusicTable \
    --item '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \
    --region us-east-2

# Step 6: Wait for a few seconds, and then check to see whether the item has been 
# successfully replicated to US East (N. Virginia) and Europe (Ireland)
aws dynamodb get-item \
    --table-name MusicTable \
    --key '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \
    --region us-east-1

aws dynamodb get-item \
    --table-name MusicTable \
    --key '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \
    --region us-east-2

# Step 7: Delete the replica table in US East (N. Virginia) Region
aws dynamodb delete-table \
    --table-name MusicTable \
    --region us-east-1

# Clean up: Delete the primary table
aws dynamodb delete-table \
    --table-name MusicTable \
    --region us-east-2
```

------

# DynamoDB tabel global keamanan
<a name="globaltables_MA_security"></a>

Replika tabel global adalah tabel DynamoDB, sehingga Anda menggunakan metode yang sama untuk mengontrol akses ke replika yang Anda lakukan untuk tabel wilayah tunggal, AWS Identity and Access Management termasuk kebijakan identitas (IAM) dan kebijakan berbasis sumber daya. Topik ini mencakup cara mengamankan tabel global multi-akun DynamoDB menggunakan izin IAM dan enkripsi (). AWS Key Management Service AWS KMS Anda mempelajari tentang kebijakan berbasis sumber daya dan peran terkait layanan (SLR) yang memungkinkan replikasi lintas akun lintas wilayah dan auto-scaling, izin IAM yang diperlukan untuk membuat, memperbarui, dan menghapus tabel global, untuk tabel Konsistensi Akhir Multi-wilayah (MREC). Anda juga mempelajari kunci AWS KMS enkripsi untuk mengelola replikasi lintas wilayah dengan aman.

Ini memberikan informasi rinci tentang kebijakan berbasis sumber daya dan izin yang diperlukan untuk membuat replikasi tabel lintas akun dan lintas wilayah. Memahami model keamanan ini sangat penting bagi pelanggan yang perlu menerapkan solusi replikasi data lintas akun yang aman.

## Otorisasi utama layanan untuk replikasi
<a name="globaltables_MA_service_principal"></a>

Tabel global multi-akun DynamoDB menggunakan pendekatan otorisasi yang berbeda karena replikasi dilakukan di seluruh batas akun. Ini dilakukan dengan menggunakan prinsip layanan replikasi DynamoDB:. `replication.dynamodb.amazonaws.com` [Setiap akun yang berpartisipasi harus secara eksplisit mengizinkan prinsipal tersebut dalam kebijakan sumber daya tabel replika, memberikan izin yang dapat dibatasi ke replika tertentu berdasarkan kondisi konteks sumber pada kunci seperti`aws:SourceAccount`,`aws:SourceArn`, dll. — lihat AWS kunci kondisi global untuk detail selengkapnya.](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html) Izin bersifat bi-directional, yang berarti bahwa semua replika harus secara eksplisit memberikan izin satu sama lain sebelum replikasi dapat dibuat di setiap pasangan replika tertentu.

Izin utama layanan berikut sangat penting untuk replikasi lintas akun:
+ `dynamodb:ReadDataForReplication`memberikan kemampuan untuk membaca data untuk tujuan replikasi. Izin ini memungkinkan perubahan dalam satu replika untuk dibaca dan disebarkan ke replika lain.
+ `dynamodb:WriteDataForReplication`memungkinkan penulisan data yang direplikasi ke tabel tujuan. Izin ini memungkinkan perubahan disinkronkan di semua replika dalam tabel global.
+ `dynamodb:ReplicateSettings`memungkinkan sinkronisasi pengaturan tabel di seluruh replika, menyediakan konfigurasi yang konsisten di semua tabel yang berpartisipasi.

Setiap replika harus memberikan izin di atas untuk semua replika lain dan untuk dirinya sendiri — yaitu kondisi konteks sumber harus menyertakan set lengkap replika yang terdiri dari tabel global. Izin ini diverifikasi untuk setiap replika baru ketika ditambahkan ke tabel global multi-akun. Ini memverifikasi bahwa operasi replikasi hanya dilakukan oleh layanan DynamoDB resmi dan hanya di antara tabel yang dimaksud.

## Peran terkait layanan untuk tabel global multi-akun
<a name="globaltables_MA_service_linked_roles"></a>

Tabel global multi-akun DynamoDB mereplikasi pengaturan di semua replika sehingga setiap replika diatur secara identik dengan throughput yang konsisten dan memberikan pengalaman fail-over yang mulus. Replikasi pengaturan dikontrol melalui `ReplicateSettings` izin pada prinsipal layanan, tetapi kami juga mengandalkan peran terkait layanan (SLRs) untuk mengelola replikasi lintas wilayah dan kemampuan auto-scaling lintas akun tertentu. Peran ini diatur hanya sekali per AWS akun. Setelah dibuat, peran yang sama melayani semua tabel global di akun Anda. Untuk informasi selengkapnya tentang peran terkait layanan, lihat [Menggunakan peran terkait layanan](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create-service-linked-role.html) di Panduan Pengguna IAM.

### Pengaturan manajemen peran terkait layanan
<a name="globaltables_MA_settings_management_slr"></a>

Amazon DynamoDB secara otomatis membuat AWSService RoleForDynamo DBGlobal TableSettingsManagement peran terkait layanan (SLR) saat Anda membuat replika tabel global multi-akun pertama di akun. Peran ini mengelola replikasi pengaturan lintas wilayah lintas akun untuk Anda.

Saat menerapkan kebijakan berbasis sumber daya ke replika, konfirmasikan bahwa Anda tidak menolak izin apa pun yang ditentukan dalam prinsip `AWSServiceRoleForDynamoDBGlobalTableSettingsManagement` ke SLR, karena hal ini dapat mengganggu pengelolaan pengaturan dan dapat mengganggu replikasi jika throughput tidak cocok di seluruh replika atau. GSIs Jika Anda menolak izin SLR yang diperlukan, replikasi ke dan dari replika yang terpengaruh dapat berhenti, dan status tabel replika akan berubah menjadi. `REPLICATION_NOT_AUTHORIZED` Untuk tabel global multi-akun, jika replika tetap dalam `REPLICATION_NOT_AUTHORIZED` status selama lebih dari 20 jam, replika dikonversi secara permanen ke tabel DynamoDB wilayah Tunggal. SLR memiliki izin berikut:
+ `application-autoscaling:DeleteScalingPolicy`
+ `application-autoscaling:DescribeScalableTargets`
+ `application-autoscaling:DescribeScalingPolicies`
+ `application-autoscaling:DeregisterScalableTarget`
+ `application-autoscaling:PutScalingPolicy`
+ `application-autoscaling:RegisterScalableTarget`

### Peran terkait layanan penskalaan otomatis
<a name="globaltables_MA_autoscaling_slr"></a>

Saat mengonfigurasi tabel global untuk mode kapasitas yang disediakan, penskalaan otomatis harus dikonfigurasi untuk tabel global. DynamoDB auto scaling menggunakan layanan Application AWS Auto Scaling untuk secara dinamis menyesuaikan kapasitas throughput yang disediakan pada replika tabel global Anda. Layanan Application Auto Scaling membuat peran terkait layanan (SLR) bernama. [AWSServiceRoleForApplicationAutoScaling\$1DynamoDBTable](https://docs.aws.amazon.com/autoscaling/application/userguide/application-auto-scaling-service-linked-roles.html) Peran terkait layanan ini secara otomatis dibuat di AWS akun Anda saat pertama kali mengonfigurasi penskalaan otomatis untuk tabel DynamoDB. Hal ini memungkinkan Application Auto Scaling untuk mengelola kapasitas tabel yang disediakan dan membuat alarm. CloudWatch 

Saat menerapkan kebijakan berbasis sumber daya ke replika, verifikasi bahwa Anda tidak menolak izin apa pun yang ditentukan dalam Kebijakan terhadap prinsipal [AWSApplicationAutoscalingDynamoDBTableApplication](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSApplicationAutoscalingDynamoDBTablePolicy.html) Auto Scaling SLR, karena ini akan mengganggu fungsionalitas auto-scaling.

## Bagaimana tabel global menggunakan AWS IAM
<a name="globaltables_MA_iam"></a>

Bagian berikut menjelaskan izin yang diperlukan untuk operasi tabel global yang berbeda dan memberikan contoh kebijakan untuk membantu Anda mengonfigurasi akses yang sesuai untuk pengguna dan aplikasi Anda.

**catatan**  
Semua izin yang dijelaskan harus diterapkan ke ARN sumber daya tabel tertentu di Wilayah yang terpengaruh. Sumber daya tabel ARN mengikuti format`arn:aws:dynamodb:region:account-id:table/table-name`, di mana Anda perlu menentukan nilai Region, ID akun, dan nama tabel yang sebenarnya.

Berikut ini adalah step-by-step topik yang kami bahas di bagian di bawah ini:
+ Membuat tabel global multi-akun dan menambahkan replika
+ Memperbarui tabel global multi-akun
+ Menghapus tabel global dan menghapus replika

### Membuat tabel global dan menambahkan replika
<a name="globaltables_MA_creating"></a>

#### Izin untuk membuat tabel global
<a name="globaltables_MA_creating_permissions"></a>

Ketika replika baru ditambahkan ke tabel regional untuk membentuk tabel global multi-akun atau ke tabel global multi-akun yang ada, prinsipal IAM yang melakukan tindakan harus diotorisasi oleh semua anggota yang ada. Semua anggota yang ada perlu memberikan izin berikut dalam kebijakan tabel mereka agar penambahan replika berhasil:
+ `dynamodb:AssociateTableReplica`- Izin ini memungkinkan tabel untuk digabungkan ke dalam pengaturan tabel global. Ini adalah izin dasar yang memungkinkan pembentukan awal hubungan replikasi.

Kontrol yang tepat ini hanya memungkinkan akun resmi untuk berpartisipasi dalam pengaturan tabel global.

#### Contoh kebijakan IAM untuk membuat tabel global
<a name="globaltables_MA_creating_examples"></a>

##### Contoh kebijakan IAM untuk pengaturan 2-replika
<a name="globaltables_MA_2replica_example"></a>

Penyiapan tabel global multi-akun mengikuti alur otorisasi tertentu yang menyediakan replikasi aman. Mari kita periksa bagaimana ini bekerja dalam praktik dengan berjalan melalui skenario praktis di mana pelanggan ingin membuat tabel global dengan dua replika. Replika pertama (ReplicaA) berada di Akun A di wilayah ap-east-1, sedangkan replika kedua (ReplicAb) ada di Akun B di wilayah eu-south-1.
+ Di akun sumber (Akun A), proses dimulai dengan membuat tabel replika utama. Administrator akun harus melampirkan kebijakan berbasis sumber daya ke tabel ini yang secara eksplisit memberikan izin yang diperlukan ke akun tujuan (Akun B) untuk melakukan asosiasi. Kebijakan ini juga mengizinkan layanan replikasi DynamoDB untuk melakukan tindakan replikasi penting.
+ Akun tujuan (Akun B) mengikuti proses serupa dengan melampirkan kebijakan berbasis sumber daya yang sesuai sambil membuat replika dan mereferensikan tabel sumber ARN yang akan digunakan untuk membuat replika. Kebijakan ini mencerminkan izin yang diberikan oleh Akun A, menciptakan hubungan dua arah tepercaya. Sebelum membuat replikasi, DynamoDB memvalidasi izin lintas akun ini untuk memverifikasi otorisasi yang tepat.

Untuk membuat pengaturan ini:
+ Administrator Akun A harus terlebih dahulu melampirkan kebijakan berbasis sumber daya ke ReplicaA. Kebijakan ini secara eksplisit memberikan izin yang diperlukan untuk Akun B dan layanan replikasi DynamoDB.
+ Demikian pula, administrator Akun B harus melampirkan kebijakan yang cocok ke ReplicAb, dengan referensi akun dibalik untuk memberikan izin yang sesuai ke Akun A, dalam panggilan buat tabel untuk membuat replika B yang merujuk replika A sebagai tabel sumber.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": [ "111122223333", "444455556666" ],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
                        "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB"
                    ]
                }
            }
        },
        {
            "Sid": "AllowTrustedAccountsToJoinThisGlobalTable",
            "Effect": "Allow",
            "Action": [
                "dynamodb:AssociateTableReplica"
            ],
            "Resource": "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
            "Principal": {"AWS": ["444455556666"]}
        }
    ]
}
```

------

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": [ "111122223333", "444455556666" ],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
                        "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB"
                    ]
                }
            }
        }
    ]
}
```

------

##### Contoh kebijakan IAM untuk penyiapan 3-replika
<a name="globaltables_MA_3replica_example"></a>

Dalam pengaturan ini, kami memiliki 3 replika ReplicaA, ReplicAb, dan ReplicaC di Akun A, Akun B, dan Akun C, masing-masing. Replica A adalah replika pertama, yang dimulai sebagai tabel regional, dan kemudian ReplicAb dan ReplicaC ditambahkan ke dalamnya.
+ Administrator Akun A harus terlebih dahulu melampirkan kebijakan berbasis sumber daya ke ReplicaA yang memungkinkan replikasi dengan semua anggota, dan mengizinkan prinsipal IAM Akun B dan Akun C untuk menambahkan replika.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": [ "111122223333", "444455556666", "123456789012" ],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
                        "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB",
                        "arn:aws:dynamodb:us-east-1:123456789012:table/ReplicaC"
                    ]
                }
            }
        },
        {
            "Sid": "AllowTrustedAccountsToJoinThisGlobalTable",
            "Effect": "Allow",
            "Action": [
                "dynamodb:AssociateTableReplica"
            ],
            "Resource": "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
            "Principal": { "AWS": [ "444455556666", "123456789012" ] }
        }
    ]
}
```

------
+ Administrator Akun B harus menambahkan replika (Replica B) yang menunjuk ke ReplicaA sebagai sumber. Replika B memiliki kebijakan berikut yang memungkinkan replikasi antara semua anggota, dan memungkinkan Akun C untuk menambahkan replika:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": [ "111122223333", "444455556666", "123456789012" ],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
                        "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB",
                        "arn:aws:dynamodb:us-east-1:123456789012:table/ReplicaC"
                    ]
                }
            }
        },
        {
            "Sid": "AllowTrustedAccountsToJoinThisGlobalTable",
            "Effect": "Allow",
            "Action": [
                "dynamodb:AssociateTableReplica"
            ],
            "Resource": "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB",
            "Principal": { "AWS": [ "123456789012" ] }
        }
    ]
}
```

------
+ Terakhir, administrator Akun C membuat replika dengan kebijakan berikut yang memungkinkan izin replikasi antara semua anggota. Kebijakan ini tidak mengizinkan replika lebih lanjut ditambahkan.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/ReplicaC",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": [ "111122223333", "444455556666" ],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
                        "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB"
                    ]
                }
            }
        }
    ]
}
```

------

### Memperbarui tabel global multi-akun
<a name="globaltables_MA_updating"></a>

Untuk mengubah setelan replika untuk tabel global yang ada menggunakan UpdateTable API, Anda memerlukan izin berikut pada sumber daya tabel di Wilayah tempat Anda melakukan panggilan API: `dynamodb:UpdateTable`

Anda juga dapat memperbarui konfigurasi tabel global lainnya, seperti kebijakan penskalaan otomatis dan pengaturan Time to Live. Izin berikut diperlukan untuk operasi pembaruan tambahan ini:

Untuk memperbarui pengaturan Waktu ke Langsung dengan `UpdateTimeToLive` API, Anda harus memiliki izin berikut pada sumber daya tabel di semua Wilayah yang berisi replika: `dynamodb:UpdateTimeToLive`

Untuk memperbarui kebijakan penskalaan otomatis replika dengan `UpdateTableReplicaAutoScaling` API, Anda harus memiliki izin berikut pada sumber daya tabel di semua Wilayah yang berisi replika:
+ `application-autoscaling:DeleteScalingPolicy`
+ `application-autoscaling:DeleteScheduledAction`
+ `application-autoscaling:DeregisterScalableTarget`
+ `application-autoscaling:DescribeScalableTargets`
+ `application-autoscaling:DescribeScalingActivities`
+ `application-autoscaling:DescribeScalingPolicies`
+ `application-autoscaling:DescribeScheduledActions`
+ `application-autoscaling:PutScalingPolicy`
+ `application-autoscaling:PutScheduledAction`
+ `application-autoscaling:RegisterScalableTarget`

**catatan**  
Anda perlu memberikan `dynamodb:ReplicateSettings` izin di semua wilayah replika dan akun agar tabel pembaruan berhasil. Jika ada replika yang tidak memberikan izin untuk mereplikasi pengaturan ke replika apa pun di tabel global multi-akun, semua operasi Pembaruan di semua replika akan gagal hingga izin diperbaiki. `AccessDeniedException`

### Menghapus tabel global dan menghapus replika
<a name="globaltables_MA_deleting"></a>

Untuk menghapus tabel global, Anda harus menghapus semua replika. Tidak seperti Tabel Global akun yang sama, Anda tidak dapat menggunakan `UpdateTable` untuk menghapus tabel replika di wilayah terpencil dan setiap replika harus dihapus melalui `DeleteTable` API dari akun yang mengontrolnya.

#### Izin untuk menghapus tabel global dan menghapus replika
<a name="globaltables_MA_deleting_permissions"></a>

Izin berikut diperlukan baik untuk menghapus replika individual dan untuk menghapus tabel global sepenuhnya. Menghapus konfigurasi tabel global hanya menghapus hubungan replikasi antara tabel di Wilayah yang berbeda. Itu tidak menghapus tabel DynamoDB yang mendasari di Wilayah terakhir yang tersisa. Tabel di Wilayah terakhir terus ada sebagai tabel DynamoDB standar dengan data dan pengaturan yang sama.

Anda memerlukan izin berikut pada sumber daya tabel di setiap Wilayah tempat Anda menghapus replika:
+ `dynamodb:DeleteTable`
+ `dynamodb:DeleteTableReplica`

## Bagaimana tabel global menggunakan AWS KMS
<a name="globaltables_MA_kms"></a>

Seperti semua tabel DynamoDB, replika tabel global selalu mengenkripsi data saat istirahat menggunakan kunci enkripsi yang disimpan AWS di Key Management Service ().AWS KMS

**catatan**  
Tidak seperti tabel global akun yang sama, replika yang berbeda dalam tabel global multi-akun dapat dikonfigurasi dengan jenis kunci yang berbeda ( AWS KMS kunci yang AWS dimiliki, atau kunci yang dikelola Pelanggan). Tabel global multi-akun tidak mendukung Kunci AWS Terkelola.

Tabel global multi-akun yang menggunakan CMKs memerlukan kebijakan kunci setiap replika untuk memberikan izin kepada prinsipal layanan replikasi DynamoDB (`replication.dynamodb.amazonaws.com`) untuk mengakses kunci untuk replikasi dan manajemen pengaturan. Izin berikut diperlukan:
+ `kms:Decrypt`
+ `kms:ReEncrypt*`
+ `kms:GenerateDataKey*`
+ `kms:DescribeKey`

**Penting**

DynamoDB memerlukan akses ke kunci enkripsi replika untuk menghapus replika. Jika Anda ingin menonaktifkan atau menghapus kunci terkelola pelanggan yang digunakan untuk mengenkripsi replika karena Anda menghapus replika, Anda harus terlebih dahulu menghapus replika, menunggu tabel dihapus dari grup replikasi dengan memanggil describe di salah satu replika lainnya, lalu nonaktifkan atau hapus kunci.

Jika Anda menonaktifkan atau mencabut akses DynamoDB ke kunci terkelola pelanggan yang digunakan untuk mengenkripsi replika, replikasi ke dan dari replika akan berhenti dan status replika akan berubah menjadi. `INACCESSIBLE_ENCRYPTION_CREDENTIALS` Jika replika tetap dalam `INACCESSIBLE_ENCRYPTION_CREDENTIALS` status selama lebih dari 20 jam, replika dikonversi secara ireversibel ke tabel DynamoDB wilayah tunggal.

### Contoh AWS KMS kebijakan
<a name="globaltables_MA_kms_example"></a>

 AWS KMS Kebijakan ini memungkinkan DynamoDB mengakses AWS KMS kedua kunci untuk replikasi antara replika A dan B. AWS KMS Kunci yang dilampirkan pada replika DynamoDB di setiap akun perlu diperbarui dengan kebijakan berikut:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": { "Service": "replication.dynamodb.amazonaws.com" },
        "Action": [
            "kms:Decrypt",
            "kms:ReEncrypt*",
            "kms:GenerateDataKey*",
            "kms:DescribeKey"
        ],
        "Resource": "*",
        "Condition": {
            "StringEquals": {
                "aws:SourceAccount": [ "111122223333", "444455556666" ],
                "aws:SourceArn": [
                    "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
                    "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB"
                ]
            }
        }
      }
   ]
 }
```

------

# Memahami penagihan Amazon DynamoDB untuk tabel global
<a name="global-tables-billing"></a>

Panduan ini menjelaskan cara kerja penagihan DynamoDB untuk tabel global, mengidentifikasi komponen yang berkontribusi pada biaya tabel global, termasuk contoh praktis. 

Tabel [global Amazon DynamoDB](GlobalTables.md) adalah database yang dikelola sepenuhnya, tanpa server, Multi-wilayah, dan multi-aktif. Tabel global dirancang untuk [ketersediaan 99,999%](https://aws.amazon.com/dynamodb/sla/), memberikan peningkatan ketahanan aplikasi, dan kelangsungan bisnis yang lebih baik. Tabel global mereplikasi tabel DynamoDB Anda secara otomatis di seluruh wilayah pilihan AWS Anda sehingga Anda dapat mencapai kinerja baca dan tulis lokal yang cepat. 

## Cara kerjanya
<a name="global-tables-billing-how-it-works"></a>

Model penagihan untuk tabel global berbeda dari tabel DynamoDB wilayah tunggal. Operasi tulis untuk tabel DynamoDB wilayah tunggal ditagih menggunakan unit berikut:
+ Tulis Unit Permintaan (WRUs) untuk mode kapasitas sesuai permintaan, di mana satu WRU dikenakan biaya untuk setiap penulisan hingga 1KB
+ Tulis Unit Kapasitas (WCUs) untuk mode kapasitas yang disediakan, di mana satu WCU menyediakan satu penulisan per detik hingga 1 KB

Saat Anda membuat tabel global dengan menambahkan tabel replika ke tabel Single-region yang ada, tabel Single-region itu menjadi tabel replika, yang berarti unit yang digunakan untuk menagih penulisan ke tabel juga berubah. Operasi tulis ke tabel replika ditagih menggunakan unit berikut: 
+ Unit Permintaan Tulis Replikasi (rWRUs) untuk mode kapasitas sesuai permintaan, di mana satu RWRU per tabel replika dikenakan biaya untuk setiap penulisan hingga 1KB
+ Unit Kapasitas Tulis Replikasi (rWCUs) untuk mode kapasitas yang disediakan, di mana satu WCU per tabel replika menyediakan satu penulisan per detik hingga 1 KB

Pembaruan untuk Global Secondary Indexes (GSIs) ditagih menggunakan unit yang sama dengan tabel DynamoDB wilayah Tunggal, bahkan jika tabel dasar untuk GSI adalah tabel replika. Operasi pembaruan untuk GSIs ditagih menggunakan unit berikut:
+ Tulis Unit Permintaan (WRUs) untuk mode kapasitas sesuai permintaan, di mana satu WRU dikenakan biaya untuk setiap penulisan hingga 1KB
+ Tulis Unit Kapasitas (WCUs) untuk mode kapasitas yang disediakan, di mana satu WCU menyediakan satu penulisan per detik hingga 1 KB

Unit tulis yang direplikasi (r WCUs dan rWRUs) dihargai sama dengan unit tulis wilayah tunggal (WCUs dan). WRUs Biaya transfer data Lintas Wilayah berlaku untuk tabel global karena data direplikasi di seluruh Wilayah. Biaya tulis yang direplikasi (RWCu atau RwRU) terjadi di setiap Wilayah yang berisi tabel replika untuk tabel global.

Membaca operasi dari tabel Single-region dan dari tabel replika menggunakan unit berikut:
+ Baca Unit Permintaan (RRUs) untuk mode kapasitas sesuai permintaan, di mana satu RRU dibebankan untuk setiap pembacaan yang sangat konsisten hingga 4KB
+ Baca Unit Kapasitas (RCUs) untuk tabel yang disediakan, di mana satu RCU menyediakan satu pembacaan per detik yang sangat konsisten hingga 4KB

## Mode konsistensi dan penagihan
<a name="global-tables-billing-consistency-modes"></a>

Unit tulis yang direplikasi (r WCUs dan rWRUs) yang digunakan untuk menagih operasi penulisan identik untuk mode konsistensi kuat Multi-wilayah (MRSC) dan Multi-region endal consistency (MREC). Tabel global yang menggunakan mode Multi-region strong consistency (MRSC) yang dikonfigurasi dengan saksi tidak menimbulkan biaya unit tulis yang direplikasi (r WCUs dan rWRUs), biaya penyimpanan, atau biaya transfer data untuk replikasi kepada saksi.

## Contoh penagihan tabel global DynamoDB
<a name="global-tables-billing-example"></a>

Mari kita telusuri skenario contoh multi-hari untuk melihat cara kerja penagihan permintaan tulis tabel global dalam praktiknya (perhatikan bahwa contoh ini hanya mempertimbangkan permintaan tulis, dan tidak termasuk pengembalian tabel dan biaya transfer data lintas wilayah yang akan dikeluarkan dalam contoh):

**Hari 1 - Tabel Wilayah Tunggal: Anda memiliki tabel** DynamoDB sesuai permintaan wilayah tunggal bernama Table\$1A di Wilayah us-west-2. Anda menulis 100 item 1KB ke Table\$1A. Untuk operasi penulisan satu wilayah ini, Anda dikenakan biaya 1 unit permintaan tulis (WRU) per 1KB tertulis. Biaya hari 1 Anda adalah:
+ 100 WRUs di Wilayah us-west-2 untuk wilayah Tunggal menulis

Total unit permintaan dibebankan pada hari 1: **100 WRUs**.

**Hari 2 - Membuat tabel global: Anda membuat tabel** global dengan menambahkan replika ke Table\$1A di Wilayah us-east-2. Table\$1A sekarang menjadi tabel global dengan dua tabel replika; satu di Wilayah us-west-2, dan satu di Wilayah us-east-2. Anda menulis 150 item 1KB ke tabel replika di Wilayah us-west-2. Biaya hari ke-2 Anda adalah:
+ 150 r WRUs di Wilayah us-west-2 untuk penulisan yang direplikasi
+ 150 r WRUs di Wilayah us-east-2 untuk penulisan yang direplikasi

Total unit permintaan dibebankan pada hari ke 2: **300 r WRUs**.

**Hari 3 - Menambahkan Indeks Sekunder Global:** Anda menambahkan indeks sekunder global (GSI) ke tabel replika di Wilayah us-east-2 yang memproyeksikan semua atribut dari tabel dasar (replika). Tabel global secara otomatis membuat GSI pada tabel replika di Wilayah us-west-2 untuk Anda. Anda menulis 200 catatan 1KB baru ke tabel replika di Wilayah us-west-2. Biaya hari ke-3 Anda adalah:
+ • 200 r WRUs di Wilayah us-west-2 untuk penulisan yang direplikasi
+ • 200 WRUs di Wilayah us-west-2 untuk pembaruan GSI
+ • 200 r WRUs di Wilayah us-east-2 untuk penulisan yang direplikasi
+ • 200 WRUs di Wilayah us-east-2 untuk pembaruan GSI

Total unit permintaan tulis dibebankan pada hari ke 3: **400 WRUs dan 400 r WRUs**.

Total biaya unit tulis untuk ketiga hari adalah 500 WRUs (100 WRU pada hari 1 \$1 400 WRUs pada hari ke 3) dan 700 r WRUs (300 r WRUs pada Hari2 \$1 400 r WRUs pada Hari 3).

Singkatnya, operasi penulisan tabel replika ditagih dalam unit tulis yang direplikasi di semua Wilayah yang berisi tabel replika. Jika Anda memiliki indeks sekunder global, Anda dikenakan biaya unit tulis untuk pembaruan GSIs di semua wilayah yang berisi GSI (yang dalam tabel global adalah semua Wilayah yang berisi tabel replika). 

# DynamoDB versi tabel global
<a name="V2globaltables_versions"></a>

Ada dua versi tabel global DynamoDB yang tersedia: Tabel Global versi 2019.11.21 (Saat Ini) dan tabel Global versi 2017.11.29 (Legacy). Kami merekomendasikan penggunaan Tabel Global versi 2019.11.21 (Saat Ini), karena lebih mudah digunakan, didukung di lebih banyak Wilayah, dan biaya lebih rendah untuk sebagian besar beban kerja dibandingkan dengan versi 2017.11.29 (Legacy).

## Menentukan versi tabel global
<a name="globaltables.DetermineVersion"></a>

### Menentukan versi menggunakan AWS CLI
<a name="globaltables.CLI"></a>

#### Mengidentifikasi versi 2019.11.21 (Saat ini) replika tabel global
<a name="globaltables.CLI.current"></a>

Untuk menentukan apakah tabel adalah replika versi tabel global 2019.11.21 (Saat ini), panggil perintah untuk tabel`describe-table`. Jika output berisi `GlobalTableVersion` atribut dengan nilai “2019.11.21", tabelnya adalah replika tabel global versi 2019.11.21 (Saat ini).

Contoh perintah CLI untuk: `describe-table`

```
aws dynamodb describe-table \
--table-name users \
--region us-east-2
```

Output (ringkasan) berisi `GlobalTableVersion` atribut dengan nilai “2019.11.21", jadi tabel ini adalah replika tabel global versi 2019.11.21 (Saat ini).

```
{
    "Table": {
        "AttributeDefinitions": [
            {
                "AttributeName": "id",
                "AttributeType": "S"
            },
            {
                "AttributeName": "name",
                "AttributeType": "S"
            }
        ],
        "TableName": "users",
        ...
        "GlobalTableVersion": "2019.11.21",
        "Replicas": [
            {
                "RegionName": "us-west-2",
                "ReplicaStatus": "ACTIVE",
            }
        ],
        ...
    }
}
```

#### Mengidentifikasi replika tabel global versi 2017.11.29 (Legacy)
<a name="globaltables.CLI.legacy"></a>

Versi tabel global 2017.11.29 (Legacy) menggunakan serangkaian perintah khusus untuk manajemen tabel global. Untuk menentukan apakah tabel adalah replika tabel global versi 2017.11.29 (Legacy), panggil perintah untuk tabel tersebut. `describe-global-table` Jika Anda menerima respons yang berhasil, tabel adalah replika tabel global versi 2017.11.29 (Legacy). Jika `describe-global-table` perintah mengembalikan `GlobalTableNotFoundException` kesalahan, tabel bukan replika versi 2017.11.29 (Legacy).

Contoh perintah CLI untuk: `describe-global-table`

```
aws dynamodb describe-global-table \
--table-name users \
--region us-east-2
```

Perintah mengembalikan respons yang berhasil, jadi tabel ini adalah replika tabel global versi 2017.11.29 (Legacy).

```
{
    "GlobalTableDescription": {
        "ReplicationGroup": [
            {
                "RegionName": "us-west-2"
            },
            {
                "RegionName": "us-east-2"
            }
        ],
        "GlobalTableArn": "arn:aws:dynamodb::123456789012:global-table/users",
        "CreationDateTime": "2025-06-10T13:55:53.630000-04:00",
        "GlobalTableStatus": "ACTIVE",
        "GlobalTableName": "users"
    }
}
```

### Menentukan versi menggunakan DynamoDB Console
<a name="globaltables.console"></a>

Untuk mengidentifikasi versi replika tabel global, lakukan hal berikut:

1. [Buka konsol DynamoDB di rumah. https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/home)

1. Di panel navigasi di sisi kiri konsol, pilih **Tabel**.

1. Pilih tabel yang ingin Anda identifikasi untuk versi tabel global.

1. Pilih tab **Tabel Global**.

   Bagian *Ringkasan* menampilkan versi tabel global yang digunakan.

## Perbedaan perilaku antara versi Legacy dan Current
<a name="DiffLegacyVsCurrent"></a>

Daftar berikut menjelaskan perbedaan perilaku antara versi Legacy dan Current dari tabel global.
+ versi 2019.11.21 (Saat ini) mengkonsumsi lebih sedikit kapasitas tulis untuk beberapa operasi DynamoDB dibandingkan dengan versi 2017.11.29 (Legacy), dan oleh karena itu, lebih hemat biaya bagi sebagian besar pelanggan. Perbedaan untuk operasi DynamoDB ini adalah sebagai berikut:
  + [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html)Memanggil item 1KB di Wilayah dan mereplikasi ke Wilayah lain membutuhkan 2 r WRUs per wilayah untuk 2017.11.29 (Warisan), tetapi hanya 1 rWRU untuk 2019.11.21 (Saat Ini).
  + Memanggil [UpdateItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html)item 1KB membutuhkan 2 r WRUs di Wilayah sumber dan 1 RwRU per Wilayah tujuan untuk 2017.11.29 (Warisan), tetapi hanya 1 rWRU untuk Wilayah sumber dan tujuan untuk 2019.11.21 (Saat Ini).
  + Memanggil [DeleteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DeleteItem.html)item 1KB membutuhkan 1 rWRU di Wilayah sumber dan 2 r WRUs per Wilayah tujuan untuk 2017.11.29 (Warisan), tetapi hanya 1 rWRU untuk Wilayah sumber atau tujuan untuk 2019.11.21 (Saat Ini).

  Tabel berikut menunjukkan konsumsi RwRU tabel 2017.11.29 (Legacy) dan 2019.11.21 (Saat Ini) untuk item 1KB di dua Wilayah.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/V2globaltables_versions.html)
+ versi 2017.11.29 (Legacy) hanya tersedia di 11. Wilayah AWS Namun, versi 2019.11.21 (Saat ini) tersedia di semua. Wilayah AWS
+ Anda membuat tabel global versi 2017.11.29 (Legacy) dengan terlebih dahulu membuat satu set tabel Regional kosong, lalu memanggil [CreateGlobalTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_CreateGlobalTable.html)API untuk membentuk tabel global. Anda membuat tabel global versi 2019.11.21 (Saat ini) dengan menjalankan [UpdateTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html)API untuk menambahkan replika ke tabel Regional yang ada.
+ versi 2017.11.29 (Legacy) mengharuskan Anda untuk mengosongkan semua replika dalam tabel sebelum menambahkan replika di Wilayah baru (termasuk selama pembuatan). versi 2019.11.21 (Saat ini) mendukung Anda untuk menambah dan menghapus replika ke Wilayah pada tabel yang sudah berisi data.
+ versi 2017.11.29 (Legacy) menggunakan kumpulan bidang APIs kontrol khusus berikut untuk mengelola replika:
  + [CreateGlobalTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_CreateGlobalTable.html)
  + [DescribeGlobalTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeGlobalTable.html)
  + [DescribeGlobalTableSettings](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeGlobalTableSettings.html)
  + [ListGlobalTables](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ListGlobalTables.html)
  + [UpdateGlobalTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateGlobalTable.html)
  + [UpdateGlobalTableSettings](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateGlobalTableSettings.html)

  versi 2019.11.21 (Saat ini) menggunakan [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html)dan [UpdateTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html) APIs untuk mengelola replika.
+ versi 2017.11.29 (Legacy) menerbitkan dua catatan DynamoDB Streams untuk setiap penulisan. versi 2019.11.21 (Saat ini) hanya menerbitkan satu catatan DynamoDB Streams untuk setiap penulisan.
+ versi 2017.11.29 (Legacy) mengisi dan memperbarui`aws:rep:deleting`,`aws:rep:updateregion`, dan `aws:rep:updatetime` atribut. versi 2019.11.21 (Saat ini) tidak mengisi atau memperbarui atribut ini.
+ versi 2017.11.29 (Legacy) tidak menyinkronkan pengaturan di seluruh replika. versi 2019.11.21 (Saat ini) menyinkronkan [Menggunakan time to live (TTL) di DynamoDB](TTL.md) pengaturan TTL di seluruh replika.
+ versi 2017.11.29 (Legacy) tidak mereplikasi penghapusan TTL ke replika lain. versi 2019.11.21 (Saat ini) mereplikasi penghapusan TTL ke semua replika.
+ versi 2017.11.29 (Legacy) tidak menyinkronkan pengaturan penskalaan [otomatis di seluruh replika. versi 2019.11.21 (Saat ini) menyinkronkan pengaturan penskalaan otomatis](AutoScaling.md) di seluruh replika.
+ versi 2017.11.29 (Legacy) tidak menyinkronkan pengaturan [indeks sekunder global (GSI) di seluruh replika. versi 2019.11.21 (Saat ini)](GSI.md) menyinkronkan pengaturan GSI di seluruh replika.
+ versi 2017.11.29 (Legacy) tidak menyinkronkan [enkripsi pada pengaturan istirahat di seluruh replika. versi 2019.11.21 (Saat ini) menyinkronkan enkripsi pada pengaturan istirahat](encryption.usagenotes.md) di seluruh replika.
+ versi 2017.11.29 (Legacy) menerbitkan metrik. versi 2019.11.21 (Saat ini) tidak mempublikasikan `PendingReplicationCount` metrik ini.

## Upgrade ke versi saat ini
<a name="upgrading-to-current-version"></a>

### Izin yang diperlukan untuk peningkatan tabel global
<a name="V2globaltables_versions.Notes-permissions"></a>

Untuk meningkatkan ke versi 2019.11.21 (Saat ini), Anda harus memiliki `dynamodb:UpdateGlobalTableversion` izin di semua Wilayah dengan replika. Izin ini diperlukan selain izin yang diperlukan untuk mengakses konsol DynamoDB dan tabel tampilan.

Kebijakan IAM berikut memberikan izin untuk memutakhirkan tabel global apa pun ke versi 2019.11.21 (Saat Ini).

```
{
    "version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "dynamodb:UpdateGlobalTableversion",
            "Resource": "*"
        }
    ]
}
```

Kebijakan IAM berikut memberikan izin untuk memutakhirkan hanya tabel `Music` global dengan replika di dua Wilayah ke versi 2019.11.21 (Saat Ini).

```
{
    "version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "dynamodb:UpdateGlobalTableversion",
            "Resource": [
                "arn:aws:dynamodb::123456789012:global-table/Music",
                "arn:aws:dynamodb:ap-southeast-1:123456789012:table/Music",
                "arn:aws:dynamodb:us-east-2:123456789012:table/Music"
            ]
        }
    ]
}
```

### Apa yang diharapkan selama upgrade
<a name="V2GlobalTablesUpgradeExpectations"></a>
+ Semua replika tabel global akan terus memproses lalu lintas baca dan tulis saat meningkatkan.
+ Proses upgrade membutuhkan antara beberapa menit hingga beberapa jam tergantung pada ukuran tabel dan jumlah replika.
+ Selama proses upgrade, nilai [TableStatus](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TableDescription.html#DDB-Type-TableDescription-TableStatus)akan berubah dari `ACTIVE` ke`UPDATING`. Anda dapat melihat status tabel dengan menjalankan [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html)API, atau dengan tampilan **Tabel di konsol DynamoDB**.
+ Penskalaan otomatis tidak akan menyesuaikan pengaturan kapasitas yang disediakan untuk tabel global saat tabel sedang ditingkatkan. Kami sangat menyarankan Anda mengatur tabel ke mode kapasitas [sesuai permintaan](capacity-mode.md#capacity-mode-on-demand) selama peningkatan.
+ Jika Anda memilih untuk menggunakan mode kapasitas [yang disediakan dengan](provisioned-capacity-mode.md) penskalaan otomatis selama peningkatan, Anda harus meningkatkan throughput baca dan tulis minimum pada kebijakan Anda untuk mengakomodasi peningkatan lalu lintas yang diharapkan untuk menghindari pembatasan selama peningkatan.
+ `ReplicationLatency`Metrik dapat melaporkan lonjakan latensi sementara atau menghentikan pelaporan data metrik selama proses peningkatan. Lihat,[ReplicationLatency](metrics-dimensions.md#ReplicationLatency), untuk informasi lebih lanjut. 
+ Ketika proses upgrade selesai, status tabel Anda akan berubah menjadi`ACTIVE`.

### Perilaku DynamoDB Streams sebelum, selama, dan setelah peningkatan
<a name="V2GlobalTablesUpgradeDDBStreamsBehavior"></a>

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/V2globaltables_versions.html)

### Memutakhirkan ke versi 2019.11.21 (Saat ini)
<a name="V2globaltables_versions.upgrade"></a>

Lakukan langkah-langkah berikut untuk memutakhirkan versi tabel global DynamoDB Anda menggunakan. Konsol Manajemen AWS

**Untuk meningkatkan tabel global ke versi 2019.11.21 (Saat ini)**

1. [Buka konsol DynamoDB di rumah. https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/home) 

1. Di panel navigasi di sisi kiri konsol, pilih **Tabel, lalu pilih tabel** global yang ingin Anda tingkatkan ke versi 2019.11.21 (Saat Ini). 

1. Pilih tab **Tabel Global**.

1. Pilih **Perbarui versi**.  
![\[Tangkapan layar konsol yang menampilkan tombol Perbarui versi.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/GlobalTables-upgrade.png)

1. Baca dan setujui persyaratan baru, lalu pilih **Perbarui versi**.

1. Setelah proses pemutakhiran selesai, versi tabel global yang muncul di konsol berubah menjadi **2019.11.21**.

# Praktik terbaik untuk tabel global
<a name="globaltables-bestpractices"></a>

Bagian berikut menjelaskan praktik terbaik untuk menyebarkan dan menggunakan tabel global.

## Versi
<a name="globaltables-bestpractices-version"></a>

[Ada dua versi tabel global DynamoDB yang tersedia: versi 2019.11.21 (Saat ini) dan versi 2017.11.29 (Legacy).](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/globaltables.V1.html) Anda harus menggunakan versi 2019.11.21 (Saat ini) bila memungkinkan. 

## Perlindungan penghapusan
<a name="globaltables-bestpractices-deletionprotection"></a>

Anda harus mengaktifkan perlindungan penghapusan pada replika tabel global yang ingin Anda lindungi dari penghapusan yang tidak disengaja. Anda harus mengaktifkan perlindungan penghapusan pada setiap replika.

## Menggunakan AWS CloudFormation
<a name="globaltables-bestpractices-cloudformation"></a>

CloudFormation saat ini tidak mendukung koordinasi sumber daya Multi-wilayah seperti tabel global di seluruh tumpukan. Jika Anda menentukan setiap replika tabel global dalam tumpukan Regional terpisah, Anda akan menemukan kesalahan karena penyimpangan terdeteksi di seluruh tumpukan saat melakukan pembaruan replika. Untuk menghindari masalah ini, Anda harus memilih satu Wilayah sebagai Wilayah referensi untuk menerapkan tabel global Anda dan menentukan semua replika tabel global Anda di tumpukan Wilayah tersebut.

**penting**  
Anda tidak dapat mengubah sumber daya jenis `AWS::DynamoDB::Table` menjadi sumber daya jenis `AWS::DynamoDB::GlobalTable` dengan mengubah jenisnya dalam templat anda. Mencoba mengonversi tabel Single-region ke tabel global dengan mengubah jenis CloudFormation sumber dayanya dapat mengakibatkan penghapusan tabel DynamoDB Anda.

Anda dapat menggunakan `AWS::DynamoDB::GlobalTable` sumber daya untuk membuat tabel dalam satu Wilayah. Tabel ini akan digunakan seperti tabel Single-region lainnya. Jika nanti Anda memperbarui tumpukan untuk menambahkan Wilayah lain ke sumber daya, replika akan ditambahkan ke tabel dan akan dikonversi dengan aman ke tabel global.

Jika Anda memiliki `AWS::DynamoDB::Table` sumber daya yang ingin Anda konversi ke `AWS::DynamoDB::GlobalTable` sumber daya, langkah-langkah yang disarankan untuk mengonversi jenis sumber daya adalah:

1. Tetapkan kebijakan `AWS::DynamoDB::Table` penghapusan untuk dipertahankan.

1. Hapus tabel dari definisi tumpukan.

1. Tambahkan replika ke tabel Single-region di AWS konsol, mengubahnya menjadi tabel global.

1. Impor tabel global baru sebagai `AWS::DynamoDB::GlobalTable` sumber daya baru ke tumpukan.

## Backup dan Recovery Point-in-Time
<a name="globaltables-bestpractices-backups"></a>

Mengaktifkan backup dan Point-in-Time Recovery otomatis (PITR) untuk satu replika dalam tabel global mungkin cukup untuk memenuhi tujuan pemulihan bencana Anda. Pencadangan replika yang dibuat dengan AWS-Backup dapat direplikasi secara otomatis di seluruh Wilayah untuk ketahanan yang lebih besar. Pertimbangkan tujuan rencana pemulihan bencana Anda dalam konteks ketersediaan tinggi Multi-wilayah saat memilih strategi pencadangan dan pemberdayaan PITR Anda.

## Merancang untuk ketersediaan tinggi Multi-wilayah
<a name="globaltables-bestpractices-multiregion"></a>

Untuk panduan preskriptif tentang penerapan tabel global, lihat Praktik [Terbaik untuk desain tabel global DynamoDB](bp-global-table-design.md).

# Bekerja dengan item dan atribut di DynamoDB
<a name="WorkingWithItems"></a>

Di Amazon DynamoDB, *item* adalah koleksi atribut. Setiap atribut mempunyai nama dan nilai. Nilai atribut dapat berupa skalar, himpunan, atau jenis dokumen. Untuk informasi selengkapnya, lihat [Amazon DynamoDB: Cara kerjanya](HowItWorks.md).

DynamoDB menyediakan empat operasi untuk fungsionalitas dasar buat, baca, perbarui, dan hapus (CRUD). Semua operasi ini bersifat atom.
+ `PutItem` — Membuat item.
+ `GetItem` — Membaca item.
+ `UpdateItem` — Memperbarui item.
+ `DeleteItem` — Menghapus item.

Setiap operasi ini mengharuskan Anda menentukan kunci primer item yang ingin Anda gunakan. Misalnya, untuk membaca item menggunakan `GetItem`, Anda harus menentukan kunci partisi dan kunci urutan (jika ada) untuk item tersebut.

Selain empat operasi CRUD dasar, DynamoDB juga menyediakan hal berikut ini:
+ `BatchGetItem` — Membaca hingga 100 item dari satu tabel atau lebih.
+ `BatchWriteItem` — Membuat atau menghapus hingga 25 item dalam satu atau beberapa tabel.

Operasi batch ini menggabungkan beberapa operasi CRUD ke dalam satu permintaan. Selain itu, operasi batch membaca dan menulis item secara paralel untuk meminimalkan latensi respons.

Bagian ini menjelaskan cara menggunakan operasi ini dan mencakup topik terkait, seperti pembaruan bersyarat dan penghitung atom. Bagian ini juga mencakup contoh kode yang menggunakan file AWS SDKs. 

**Topics**
+ [Ukuran dan format item DynamoDB](CapacityUnitCalculations.md)
+ [Membaca item](#WorkingWithItems.ReadingData)
+ [Menulis item](#WorkingWithItems.WritingData)
+ [Nilai yang dikembalikan](#WorkingWithItems.ReturnValues)
+ [Operasi batch](#WorkingWithItems.BatchOperations)
+ [Penghitung atom](#WorkingWithItems.AtomicCounters)
+ [Penulisan bersyarat](#WorkingWithItems.ConditionalUpdate)
+ [Menggunakan ekspresi di DynamoDB](Expressions.md)
+ [Menggunakan time to live (TTL) di DynamoDB](TTL.md)
+ [Menanyakan tabel di DynamoDB](Query.md)
+ [Memindai tabel di DynamoDB](Scan.md)
+ [PartiQL - Bahasa kueri yang kompatibel dengan SQL untuk Amazon DynamoDB](ql-reference.md)
+ [Bekerja dengan item: Java](JavaDocumentAPIItemCRUD.md)
+ [Bekerja dengan item: .NET](LowLevelDotNetItemCRUD.md)

# Ukuran dan format item DynamoDB
<a name="CapacityUnitCalculations"></a>

Tabel DynamoDB tidak memiliki skema, kecuali kunci primer, sehingga semua item dalam tabel dapat memiliki atribut, ukuran, dan jenis data yang berbeda.

Ukuran total suatu item adalah jumlah panjang nama dan nilai atributnya, ditambah overhead yang berlaku seperti dijelaskan di bawah. Anda dapat menggunakan panduan berikut untuk memperkirakan ukuran atribut:
+ String adalah Unicode dengan pengodean biner UTF-8. Ukuran string adalah *(jumlah byte UTF-8 yang dikodekan dari nama atribut) \$1 (jumlah byte yang dikodekan UTF-8)*.
+ Angka memiliki panjang yang bervariasi, hingga 38 angka penting. Angka nol di depan dan di belakang dipangkas. Ukuran angka kira-kira *(jumlah byte yang dikodekan UTF-8 dari nama atribut) \$1 (1 byte per dua digit signifikan) \$1 (1 byte*).
+ Nilai biner harus dikodekan dalam format base64 sebelum dapat dikirim ke DynamoDB, namun panjang byte mentah nilai tersebut digunakan untuk menghitung ukuran. Ukuran atribut biner adalah *(jumlah byte UTF-8 yang dikodekan dari nama atribut) \$1 (jumlah byte mentah)*.
+ Ukuran atribut null atau atribut Boolean adalah *(jumlah byte UTF-8 yang dikodekan dari nama atribut) \$1 (1 byte*).
+ Atribut jenis `List` atau `Map` memerlukan overhead 3 byte, apa pun kontennya. Ukuran a `List` or `Map` is *(jumlah byte UTF-8 yang dikodekan dari nama atribut) \$1 jumlah (ukuran elemen bersarang) \$1 (3 byte*). Ukuran kosong `List` atau `Map` is *(jumlah byte UTF-8 yang dikodekan dari nama atribut) \$1 (3 byte)*.
+ Masing-masing elemen `List` atau `Map` juga membutuhkan 1 byte overhead.

**catatan**  
Sebaiknya Anda memilih nama atribut yang lebih pendek. Ini membantu Anda mengurangi jumlah penyimpanan yang dibutuhkan, tetapi juga dapat menurunkan jumlah yang RCU/WCUs Anda gunakan.

Untuk tujuan penagihan penyimpanan, setiap item mencakup overhead penyimpanan per item yang bergantung pada fitur yang telah Anda aktifkan.
+ Semua item di DynamoDB memerlukan overhead penyimpanan sebesar 100 byte untuk pengindeksan.
+ Beberapa fitur DynamoDB (tabel global, transaksi, perubahan pengambilan data untuk Kinesis Data Streams dengan DynamoDB) memerlukan overhead penyimpanan tambahan untuk memperhitungkan atribut yang dibuat sistem akibat pengaktifan fitur tersebut. Misalnya, tabel global memerlukan tambahan overhead penyimpanan sebesar 48 byte.

## Membaca item
<a name="WorkingWithItems.ReadingData"></a>

Untuk membaca item dari tabel DynamoDB, gunakan operasi `GetItem`. Anda harus memberikan nama tabel, beserta kunci primer item yang Anda inginkan.

**Example**  
 AWS CLI Contoh berikut menunjukkan cara membaca item dari `ProductCatalog` tabel.  

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"1"}}'
```

**catatan**  
Dengan `GetItem`, Anda harus menentukan *seluruh* kunci primer, bukan hanya sebagian darinya. Misalnya, jika tabel memiliki kunci primer gabungan (kunci partisi dan kunci urutan), Anda harus menyediakan nilai untuk kunci partisi dan nilai untuk kunci urutan.

Pada akhirnya, permintaan `GetItem` melakukan pembacaan konsisten secara default. Sebagai gantinya, Anda dapat menggunakan parameter `ConsistentRead` untuk meminta bacaan sangat konsisten. (Ini mengkonsumsi unit kapasitas baca tambahan, tetapi mengembalikan sebagian besar up-to-date versi item.)

`GetItem` mengembalikan semua atribut item. Anda dapat menggunakan *ekspresi proyeksi* untuk mengembalikan sebagian atribut saja. Untuk informasi selengkapnya, lihat [Menggunakan ekspresi proyeksi di DynamoDB](Expressions.ProjectionExpressions.md).

Untuk mengembalikan jumlah unit kapasitas baca yang dikonsumsi oleh `GetItem`, tetapkan parameter `ReturnConsumedCapacity` menjadi `TOTAL`.

**Example**  
Berikut AWS Command Line Interface (AWS CLI) contoh menunjukkan beberapa `GetItem` parameter opsional.  

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"1"}}' \
    --consistent-read \
    --projection-expression "Description, Price, RelatedItems" \
    --return-consumed-capacity TOTAL
```

## Menulis item
<a name="WorkingWithItems.WritingData"></a>

Untuk membuat, memperbarui, atau menghapus item dalam tabel DynamoDB, gunakan salah satu operasi berikut:
+ `PutItem`
+ `UpdateItem`
+ `DeleteItem`

Untuk setiap operasi ini, Anda harus menentukan seluruh kunci primer, bukan hanya sebagian saja. Misalnya, jika tabel memiliki kunci primer gabungan (kunci partisi dan kunci urutan), Anda harus memberikan nilai untuk kunci partisi dan nilai untuk kunci urutan.

Untuk mengembalikan jumlah unit kapasitas tulis yang digunakan oleh salah satu operasi ini, atur parameter `ReturnConsumedCapacity` ke salah satu dari berikut ini: 
+ `TOTAL` — Mengembalikan jumlah total unit kapasitas tulis yang dikonsumsi.
+ `INDEXES` — Mengembalikan jumlah total unit kapasitas tulis yang digunakan, dengan subtotal untuk tabel dan indeks sekunder apa pun yang terpengaruh oleh operasi.
+ `NONE` — Tidak ada detail kapasitas tulis dikembalikan. (Ini adalah pengaturan default.)

### PutItem
<a name="WorkingWithItems.WritingData.PutItem"></a>

`PutItem` membuat item baru. Jika item dengan kunci yang sama sudah ada di tabel, item tersebut akan diganti dengan item baru.

**Example**  
Tulis item baru ke tabel `Thread`. Kunci primer untuk `Thread` terdiri dari `ForumName` (kunci partisi) dan `Subject` (kunci urutan).  

```
aws dynamodb put-item \
    --table-name Thread \
    --item file://item.json
```
Argumen untuk `--item` disimpan dalam file `item.json`.  

```
{
    "ForumName": {"S": "Amazon DynamoDB"},
    "Subject": {"S": "New discussion thread"},
    "Message": {"S": "First post in this thread"},
    "LastPostedBy": {"S": "fred@example.com"},
    "LastPostDateTime": {"S": "201603190422"}
}
```

### UpdateItem
<a name="WorkingWithItems.WritingData.UpdateItem"></a>

Jika item dengan kunci tertentu tidak ada, `UpdateItem` akan membuat item baru. Jika tidak, ini akan mengubah atribut item yang sudah ada.

Anda menggunakan *ekspresi pembaruan* untuk menentukan atribut yang ingin Anda ubah dan nilai barunya. Untuk informasi selengkapnya, lihat [Menggunakan ekspresi pembaruan di DynamoDB](Expressions.UpdateExpressions.md). 

Dalam ekspresi pembaruan, Anda menggunakan nilai atribut ekspresi sebagai pengganti nilai aktual. Untuk informasi selengkapnya, lihat [Menggunakan nilai atribut ekspresi di DynamoDB](Expressions.ExpressionAttributeValues.md).

**Example**  
Modifikasi berbagai atribut dalam item `Thread`. Parameter `ReturnValues` opsional menunjukkan item seperti yang muncul setelah pembaruan. Untuk informasi selengkapnya, lihat [Nilai yang dikembalikan](#WorkingWithItems.ReturnValues).  

```
aws dynamodb update-item \
    --table-name Thread \
    --key file://key.json \
    --update-expression "SET Answered = :zero, Replies = :zero, LastPostedBy = :lastpostedby" \
    --expression-attribute-values file://expression-attribute-values.json \
    --return-values ALL_NEW
```

Argumen untuk `--key` disimpan dalam file `key.json`.

```
{
    "ForumName": {"S": "Amazon DynamoDB"},
    "Subject": {"S": "New discussion thread"}
}
```

Argumen untuk `--expression-attribute-values` disimpan dalam file `expression-attribute-values.json`.

```
{
    ":zero": {"N":"0"},
    ":lastpostedby": {"S":"barney@example.com"}
}
```

### DeleteItem
<a name="WorkingWithItems.WritingData.DeleteItem"></a>

`DeleteItem` menghapus item dengan kunci tertentu.

**Example**  
 AWS CLI Contoh berikut menunjukkan cara menghapus `Thread` item.  

```
aws dynamodb delete-item \
    --table-name Thread \
    --key file://key.json
```

## Nilai yang dikembalikan
<a name="WorkingWithItems.ReturnValues"></a>

Dalam beberapa kasus, Anda mungkin ingin DynamoDB mengembalikan nilai-nilai atribut tertentu seperti nilai yang muncul sebelum atau setelah Anda memodifikasi mereka. Operasi `PutItem`, `UpdateItem`, dan `DeleteItem` memiliki parameter `ReturnValues` yang dapat Anda gunakan untuk mengembalikan nilai atribut sebelum atau setelah dimodifikasi.

Nilai default untuk `ReturnValues` adalah `NONE`, yang berarti DynamoDB tidak mengembalikan informasi apa pun tentang atribut yang dimodifikasi. 

Berikut ini adalah pengaturan valid lainnya untuk `ReturnValues`, yang diatur oleh operasi DynamoDB API.

### PutItem
<a name="WorkingWithItems.ReturnValues.PutItem"></a>
+ `ReturnValues`: `ALL_OLD`
  + Jika Anda menimpa item yang ada, `ALL_OLD` akan mengembalikan seluruh item seperti item yang muncul sebelum penimpaan.
  + Jika Anda menulis item yang tidak ada, `ALL_OLD` tidak akan berpengaruh.

### UpdateItem
<a name="WorkingWithItems.ReturnValues.UpdateItem"></a>

Penggunaan yang paling umum untuk `UpdateItem` adalah untuk memperbarui item yang ada. Namun, `UpdateItem` benar-benar melakukan *upsert*, yang berarti bahwa ini secara otomatis membuat item jika sudah tidak ada.
+ `ReturnValues`: `ALL_OLD`
  + Jika Anda memperbarui item yang ada, `ALL_OLD` akan mengembalikan seluruh item seperti item yang muncul sebelum pembaruan.
  + Jika Anda memperbarui item yang tidak ada (upsert), `ALL_OLD` tidak akan berpengaruh.
+ `ReturnValues`: `ALL_NEW`
  + Jika Anda memperbarui item yang ada, `ALL_NEW` menampilkan seluruh item seperti item yang muncul setelah pembaruan.
  + Jika Anda memperbarui item tidak ada (upsert), `ALL_NEW` akan mengembalikan seluruh item.
+ `ReturnValues`: `UPDATED_OLD`
  + Jika Anda memperbarui item yang ada, `UPDATED_OLD` hanya mengembalikan atribut yang diperbarui seperti atribut yang muncul sebelum pembaruan.
  + Jika Anda memperbarui item yang tidak ada (upsert), `UPDATED_OLD` tidak akan berpengaruh.
+ `ReturnValues`: `UPDATED_NEW`
  + Jika Anda memperbarui item yang ada, `UPDATED_NEW` hanya menampilkan atribut yang terpengaruh, seperti yang muncul setelah pembaruan.
  + Jika Anda memperbarui item tidak ada (upsert), `UPDATED_NEW` hanya mengembalikan atribut diperbarui, seperti yang muncul setelah pembaruan.

### DeleteItem
<a name="WorkingWithItems.ReturnValues.DeleteItem"></a>
+ `ReturnValues`: `ALL_OLD`
  + Jika Anda menghapus item yang ada, `ALL_OLD` akan mengembalikan seluruh item seperti yang muncul sebelum Anda menghapusnya.
  + Jika Anda menghapus item yang tidak ada, `ALL_OLD` tidak akan menampilkan data apa pun.

## Operasi batch
<a name="WorkingWithItems.BatchOperations"></a>

Untuk aplikasi yang memerlukan membaca atau menulis beberapa item, DynamoDB menyediakan operasi `BatchGetItem` dan `BatchWriteItem`. Dengan menggunakan operasi ini, Anda dapat mengurangi jumlah perjalanan bolak-balik jaringan dari aplikasi Anda ke DynamoDB. Selain itu, DynamoDB melakukan operasi baca atau tulis individu secara paralel. Aplikasi Anda mendapatkan keuntungan dari paralelisme ini tanpa perlu mengelola konkurensi atau threading.

Operasi batch pada dasarnya merupakan pembungkus di sekitar beberapa permintaan baca atau tulis. Misalnya, jika permintaan `BatchGetItem` berisi lima item, DynamoDB melakukan lima operasi `GetItem` atas nama Anda. Demikian pula, jika permintaan `BatchWriteItem` berisi dua permintaan put dan empat permintaan penghapusan, DynamoDB akan melakukan dua permintaan `PutItem` dan empat `DeleteItem`.

Secara umum, operasi batch tidak gagal kecuali *semua* permintaan dalam batch mengalami kegagalan. Misalnya, bayangkan Anda melakukan operasi `BatchGetItem`, tetapi salah satu permintaan `GetItem` individu dalam batch mengalami kegagalan. Dalam kasus ini, `BatchGetItem` mengembalikan kunci dan data dari permintaan `GetItem` yang gagal. Permintaan `GetItem` lainnya dalam batch tidak akan terpengaruh.

### BatchGetItem
<a name="WorkingWithItems.BatchOperations.BatchGetItem"></a>

Satu operasi `BatchGetItem` dapat berisi hingga 100 permintaan `GetItem` individu dapat mengambil data hingga 16 MB. Selain itu, operasi `BatchGetItem` dapat mengambil item dari beberapa tabel.

**Example**  
Ambil dua item dari tabel `Thread`, menggunakan ekspresi proyeksi untuk mengembalikan beberapa atribut saja.  

```
aws dynamodb batch-get-item \
    --request-items file://request-items.json
```
Argumen untuk `--request-items` disimpan dalam file `request-items.json`.  

```
{
    "Thread": {
        "Keys": [
            {
                "ForumName":{"S": "Amazon DynamoDB"},
                "Subject":{"S": "DynamoDB Thread 1"}
            },
            {
                "ForumName":{"S": "Amazon S3"},
                "Subject":{"S": "S3 Thread 1"}
            }
        ],
        "ProjectionExpression":"ForumName, Subject, LastPostedDateTime, Replies"
    }
}
```

### BatchWriteItem
<a name="WorkingWithItems.BatchOperations.BatchWriteItem"></a>

Operasi `BatchWriteItem` dapat berisi hingga 25 permintaan `PutItem` dan `DeleteItem` individu, serta dapat menulis data hingga 16 MB. (Ukuran maksimum item individu adalah sebesar 400 KB.) Selain itu, operasi `BatchWriteItem` dapat menempatkan atau menghapus item dalam beberapa tabel. 

**catatan**  
`BatchWriteItem` tidak mendukung permintaan `UpdateItem`.

**Example**  
Tulis dua item ke tabel `ProductCatalog`.  

```
aws dynamodb batch-write-item \
    --request-items file://request-items.json
```
Argumen untuk `--request-items` disimpan dalam file `request-items.json`.  

```
{
    "ProductCatalog": [
        {
            "PutRequest": {
                "Item": {
                    "Id": { "N": "601" },
                    "Description": { "S": "Snowboard" },
                    "QuantityOnHand": { "N": "5" },
                    "Price": { "N": "100" }
                }
            }
        },
        {
            "PutRequest": {
                "Item": {
                    "Id": { "N": "602" },
                    "Description": { "S": "Snow shovel" }
                }
            }
        }
    ]
}
```

## Penghitung atom
<a name="WorkingWithItems.AtomicCounters"></a>

Anda dapat menggunakan operasi `UpdateItem` untuk mengimplementasikan *penghitung atom*—atribut numerik yang bertambah, tanpa syarat, tanpa mengganggu permintaan tulis lainnya. (Semua permintaan tulis diterapkan sesuai urutan penerimaannya.) Dengan penghitung atom, pembaruan tidak idempotent. Dengan kata lain, nilai numerik bertambah atau berkurang setiap kali Anda menelepon. `UpdateItem` Jika nilai kenaikan yang digunakan untuk memperbarui penghitung atom positif, maka itu dapat menyebabkan penghitungan berlebihan. Jika nilai kenaikan negatif, maka dapat menyebabkan kekurangan perhitungan.

Anda dapat menggunakan penghitung atom untuk melacak jumlah pengunjung ke situs web. Dalam hal ini, aplikasi Anda akan menaikkan nilai numerik, terlepas dari nilai saat ini. Jika operasi `UpdateItem` gagal, aplikasi hanya dapat mencoba ulang operasi. Tindakan ini akan berisiko memperbarui penghitung dua kali, tetapi Anda mungkin bisa menoleransi sedikit kelebihan penghitungan atau kekurangan penghitungan dari pengunjung situs web.

Penghitung atom tidak akan cocok ketika kelebihan penghitungan atau kekurangan penghitungan tidak dapat ditoleransi (misalnya, dalam aplikasi perbankan). Dalam kasus ini, lebih aman menggunakan pembaruan bersyarat, bukannya penghitung atom.

Untuk informasi selengkapnya, lihat [Menambahkan dan mengurangi atribut numerik](Expressions.UpdateExpressions.md#Expressions.UpdateExpressions.SET.IncrementAndDecrement).

**Example**  
 AWS CLI Contoh berikut menambah produk `Price` sebesar 5. Untuk contoh ini, item diketahui ada sebelum penghitung diperbarui. Karena `UpdateItem` tidak idempotent, `Price` meningkat setiap kali Anda menjalankan kode ini.   

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id": { "N": "601" }}' \
    --update-expression "SET Price = Price + :incr" \
    --expression-attribute-values '{":incr":{"N":"5"}}' \
    --return-values UPDATED_NEW
```

## Penulisan bersyarat
<a name="WorkingWithItems.ConditionalUpdate"></a>

*Secara default, operasi penulisan DynamoDB `PutItem` (`DeleteItem`,) tidak bersyarat: Setiap operasi menimpa item yang ada yang memiliki kunci primer yang ditentukan.*

DynamoDB secara opsional mendukung penulisan bersyarat untuk operasi ini. Penulisan bersyarat akan berhasil hanya jika atribut item memenuhi satu atau beberapa kondisi yang diharapkan. Jika tidak, operasi ini akan mengembalikan kesalahan.

Penulisan bersyarat memeriksa kondisinya terhadap versi item yang terbaru diperbarui. Perhatikan bahwa jika item sebelumnya tidak ada atau jika operasi sukses terbaru terhadap item tersebut adalah penghapusan, maka penulisan bersyarat tidak akan menemukan item sebelumnya.

 Penulisan bersyarat sangat membantu dalam banyak situasi. Misalnya, Anda mungkin ingin operasi `PutItem` bisa berhasil hanya jika sudah tidak ada item dengan kunci primer yang sama. Atau Anda dapat mencegah operasi `UpdateItem` memodifikasi item jika salah satu atributnya memiliki nilai tertentu.

Penulisan bersyarat berguna jika beberapa pengguna mencoba mengubah item yang sama. Perhatikan diagram berikut, di mana dua pengguna (Alice dan Bob) bekerja dengan item yang sama dari tabel DynamoDB.

![\[Pengguna Alice dan Bob mencoba memodifikasi item dengan Id 1, menunjukkan perlunya penulisan bersyarat.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/update-no-condition.png)


Misalkan Alice menggunakan AWS CLI untuk memperbarui `Price` atribut ke 8.

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"1"}}' \
    --update-expression "SET Price = :newval" \
    --expression-attribute-values file://expression-attribute-values.json
```

Argumen untuk `--expression-attribute-values` disimpan dalam file `expression-attribute-values.json`:

```
{
    ":newval":{"N":"8"}
}
```

Sekarang anggaplah Bob mengeluarkan permintaan `UpdateItem` yang serupa kemudian, tetapi mengubah `Price` menjadi 12. Untuk Bob, parameter `--expression-attribute-values` akan terlihat seperti berikut ini.

```
{
    ":newval":{"N":"12"}
}
```

Permintaan Bob berhasil, tetapi pembaruan Alice sebelumnya hilang.

Untuk meminta `PutItem`, `DeleteItem`, atau `UpdateItem` bersyarat, Andalah yang menentukan ekspresi kondisi. *Ekspresi kondisi* adalah string yang berisi nama atribut, operator bersyarat, dan fungsi bawaan. Seluruh ekspresi harus bernilai benar. Jika tidak, operasi gagal.

Sekarang pertimbangkan diagram berikut yang menunjukkan bagaimana penulisan bersyarat akan mencegah pembaruan Alice ditimpa.

![\[Penulisan bersyarat mencegah pembaruan pengguna Bob menimpa perubahan pengguna Alice ke item yang sama.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/update-yes-condition.png)


Alice mencoba pertama kali untuk memperbarui `Price` menjadi 8, tetapi hanya jika `Price` saat ini adalah 10.

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"1"}}' \
    --update-expression "SET Price = :newval" \
    --condition-expression "Price = :currval" \
    --expression-attribute-values file://expression-attribute-values.json
```

Argumen untuk `--expression-attribute-values` disimpan dalam file `expression-attribute-values.json`.

```
{
    ":newval":{"N":"8"},
    ":currval":{"N":"10"}
}
```

Pembaruan Alice berhasil karena kondisi bernilai benar.

Berikutnya, Bob mencoba memperbarui `Price` menjadi 12, tetapi hanya jika `Price` saat ini adalah 10. Untuk Bob, parameter `--expression-attribute-values` akan terlihat seperti berikut ini.

```
{
    ":newval":{"N":"12"},
    ":currval":{"N":"10"}
}
```

Karena Alice sebelumnya telah mengubah `Price` ke 8, ekspresi kondisi bernilai SALAH, dan pembaruan Bob mengalami kegagalan.

Untuk informasi selengkapnya, lihat [Contoh CLI ekspresi kondisi DynamoDB](Expressions.ConditionExpressions.md).

### Idempotensi penulisan bersyarat
<a name="WorkingWithItems.ConditionalWrites.Idempotence"></a>

Penulisan bersyarat dapat menjadi *idempotent* jika pemeriksaan bersyarat berada pada atribut yang sama dan sedang diperbarui. Ini berarti bahwa DynamoDB melakukan permintaan tulis yang diberikan hanya jika nilai atribut tertentu dalam item cocok dengan tempat mereka berada pada saat permintaan sesuai harapan Anda. 

Misalnya, misalnya Anda mengeluarkan permintaan `UpdateItem` untuk meningkatkan `Price` dari item sebesar 3, tetapi hanya jika `Price` saat ini adalah 20. Setelah Anda mengirimkan permintaan, tetapi sebelum Anda mendapatkan hasil kembali, terjadi kesalahan jaringan, dan Anda tidak tahu apakah permintaan tersebut berhasil. Karena penulisan bersyarat ini idempotent, Anda dapat mencoba kembali permintaan `UpdateItem` yang sama, dan DynamoDB memperbarui item hanya jika `Price` saat ini adalah 20.

### Unit kapasitas yang digunakan oleh penulisan bersyarat
<a name="WorkingWithItems.ConditionalWrites.ReturnConsumedCapacity"></a>

Jika `ConditionExpression` bernilai false selama penulisan bersyarat, DynamoDB masih menggunakan kapasitas tulis dari tabel. Jumlah yang dikonsumsi tergantung dari besar kecilnya barang yang ada (atau minimal 1). Misalnya, jika item yang ada berukuran 300kb dan item baru yang Anda coba buat atau perbarui berukuran 310kb, unit kapasitas tulis yang digunakan akan menjadi 300 jika kondisi gagal, dan 310 jika kondisi berhasil. Jika ini adalah item baru (belum ada item yang ada), maka unit kapasitas tulis yang digunakan adalah 1 jika kondisi gagal dan 310 jika kondisi berhasil.

**catatan**  
Operasi tulis hanya mengonsumsi unit kapasitas *tulis*. Operasi tersebut tidak pernah mengonsumsi unit kapasitas *baca*.

Penulisan bersyarat yang gagal akan menampilkan `ConditionalCheckFailedException`. Ketika ini terjadi, Anda tidak menerima informasi apa pun dalam tanggapan tentang kapasitas tulis yang dikonsumsi.

Untuk mengembalikan jumlah unit kapasitas tulis yang dikonsumsi selama penulisan bersyarat, Anda menggunakan parameter `ReturnConsumedCapacity`:
+ `TOTAL` — Mengembalikan jumlah total unit kapasitas tulis yang dikonsumsi.
+ `INDEXES` — Mengembalikan jumlah total unit kapasitas tulis yang digunakan, dengan subtotal untuk tabel dan indeks sekunder apa pun yang terpengaruh oleh operasi.
+ `NONE` — Tidak ada detail kapasitas tulis dikembalikan. (Ini menjadi opsi default.)

  

**catatan**  
Tidak seperti indeks sekunder global, indeks sekunder lokal berbagi kapasitas throughput yang disediakan dengan tabelnya. Aktivitas baca dan tulis pada indeks sekunder lokal mengonsumsi kapasitas throughput yang disediakan dari tabel.

# Menggunakan ekspresi di DynamoDB
<a name="Expressions"></a>

Di Amazon DynamoDB, Anda dapat *menggunakan* ekspresi untuk menentukan atribut mana yang akan dibaca dari item, menulis data saat kondisi terpenuhi, menentukan cara memperbarui item, menentukan kueri, dan memfilter hasil kueri.

Tabel ini menjelaskan tata bahasa ekspresi dasar dan jenis ekspresi yang tersedia.


| Jenis ekspresi | Deskripsi | 
| --- | --- | 
| Ekspresi proyeksi | Ekspresi proyeksi mengidentifikasi atribut yang ingin Anda ambil dari item saat Anda menggunakan operasi seperti GetItem, Kueri, atau Pindai. | 
| Ekspresi kondisi | Ekspresi kondisi menentukan item mana yang harus dimodifikasi saat Anda menggunakan PutItem, UpdateItem, dan DeleteItem operasi. | 
| Perbarui ekspresi | Ekspresi pembaruan menentukan bagaimana UpdateItem akan memodifikasi atribut item— misalnya, menetapkan nilai skalar atau menghapus elemen dari daftar atau peta. | 
| Ekspresi kondisi kunci | Ekspresi kondisi kunci menentukan item mana yang akan dibaca kueri dari tabel atau indeks. | 
| Ekspresi filter | Ekspresi filter menentukan item mana di antara hasil Query yang harus dikembalikan kepada Anda. Semua hasil lainnya dibuang. | 

Untuk informasi tentang sintaks ekspresi dan informasi lebih rinci tentang setiap jenis ekspresi, lihat bagian berikut.

**Topics**
+ [Mengacu pada atribut item saat menggunakan ekspresi di DynamoDB](Expressions.Attributes.md)
+ [Nama atribut ekspresi (alias) di DynamoDB](Expressions.ExpressionAttributeNames.md)
+ [Menggunakan nilai atribut ekspresi di DynamoDB](Expressions.ExpressionAttributeValues.md)
+ [Menggunakan ekspresi proyeksi di DynamoDB](Expressions.ProjectionExpressions.md)
+ [Menggunakan ekspresi pembaruan di DynamoDB](Expressions.UpdateExpressions.md)
+ [Kondisi dan filter ekspresi, operator, dan fungsi di DynamoDB](Expressions.OperatorsAndFunctions.md)
+ [Contoh CLI ekspresi kondisi DynamoDB](Expressions.ConditionExpressions.md)

**catatan**  
Untuk kompatibilitas ke belakang, DynamoDB juga mendukung parameter bersyarat yang tidak menggunakan ekspresi. Untuk informasi selengkapnya, lihat [Parameter bersyarat DynamoDB lama](LegacyConditionalParameters.md).  
Aplikasi baru harus menggunakan ekspresi, bukan parameter warisan.

# Mengacu pada atribut item saat menggunakan ekspresi di DynamoDB
<a name="Expressions.Attributes"></a>

Bagian ini menjelaskan cara merujuk ke atribut item dalam suatu ekspresi di Amazon DynamoDB. Anda dapat bekerja dengan atribut apa pun, meskipun itu sangat bersarang dalam beberapa daftar dan peta.

**Topics**
+ [Atribut tingkat atas](#Expressions.Attributes.TopLevelAttributes)
+ [Atribut bersarang](#Expressions.Attributes.NestedAttributes)
+ [Jalur dokumen](#Expressions.Attributes.NestedElements.DocumentPathExamples)

**Item Sampel: ProductCatalog**  
Contoh di halaman ini menggunakan item contoh berikut dalam `ProductCatalog` tabel. (Tabel ini dijelaskan dalam [Contoh tabel dan data untuk digunakan di DynamoDB](AppendixSampleTables.md).)

```
{
    "Id": 123,
    "Title": "Bicycle 123",
    "Description": "123 description",
    "BicycleType": "Hybrid",
    "Brand": "Brand-Company C",
    "Price": 500,
    "Color": ["Red", "Black"],
    "ProductCategory": "Bicycle",
    "InStock": true,
    "QuantityOnHand": null,
    "RelatedItems": [
        341,
        472,
        649
    ],
    "Pictures": {
        "FrontView": "http://example.com/products/123_front.jpg",
        "RearView": "http://example.com/products/123_rear.jpg",
        "SideView": "http://example.com/products/123_left_side.jpg"
    },
    "ProductReviews": {
	    "FiveStar": [
	    		"Excellent! Can't recommend it highly enough! Buy it!",
	    		"Do yourself a favor and buy this."
	    ],
	    "OneStar": [
	    		"Terrible product! Do not buy this."
	    ]
    },
    "Comment": "This product sells out quickly during the summer",
    "Safety.Warning": "Always wear a helmet"
 }
```

Perhatikan hal-hal berikut:
+ Nilai kunci partisi (`Id`) adalah `123`. Tidak ada kunci urutan.
+ Sebagian besar atribut memiliki jenis daya skalar, seperti `String`, `Number`, `Boolean`, dan `Null`.
+ Satu atribut (`Color`) adalah `String Set`.
+ Atribut berikut adalah jenis daya dokumen:
  + Daftar dari `RelatedItems`. Setiap elemen adalah `Id` untuk produk terkait.
  + Peta dari `Pictures`. Setiap elemen adalah deskripsi singkat dari gambar, bersama dengan URL untuk file gambar yang sesuai.
  + Peta dari `ProductReviews`. Setiap elemen mewakili penilaian dan daftar ulasan yang sesuai dengan penilaian tersebut. Awalnya, peta ini diisi dengan ulasan bintang lima dan bintang satu.

## Atribut tingkat atas
<a name="Expressions.Attributes.TopLevelAttributes"></a>

Suatu atribut dikatakan *tingkat atas* jika tidak melekat pada atribut lain. Untuk item `ProductCatalog`, atribut tingkat atas adalah sebagai berikut:
+ `Id`
+ `Title`
+ `Description`
+ `BicycleType`
+ `Brand`
+ `Price`
+ `Color`
+ `ProductCategory`
+ `InStock`
+ `QuantityOnHand`
+ `RelatedItems`
+ `Pictures`
+ `ProductReviews`
+ `Comment`
+ `Safety.Warning`

Semua atribut tingkat atas ini bersifat skalar, kecuali untuk `Color` (daftar), `RelatedItems` (daftar), `Pictures` (peta), dan `ProductReviews` (peta).

## Atribut bersarang
<a name="Expressions.Attributes.NestedAttributes"></a>

Suatu atribut dikatakan *bersarang* jika melekat pada atribut lain. Untuk mengakses atribut bersarang, Anda menggunakan *operator dereferensi*:
+ `[n]` — untuk elemen daftar
+ `.` (titik) — untuk elemen peta

### Mengakses elemen daftar
<a name="Expressions.Attributes.NestedElements.AccessingListElements"></a>

Operator dereferensi untuk elemen daftar adalah **[*N*]**, dengan *n* adalah nomor elemen. Elemen daftar berbasis nol, sehingga [0] mewakili elemen pertama dalam daftar, [1] mewakili elemen kedua, dan seterusnya. Berikut ini adalah beberapa contohnya:
+ `MyList[0]`
+ `AnotherList[12]`
+ `ThisList[5][11]`

Elemen `ThisList[5]` itu sendiri adalah daftar bersarang. Karena itu, `ThisList[5][11]` merujuk pada elemen ke-12 dalam daftar itu.

Angka di dalam tanda kurung siku harus berupa angka bulat bukan negatif. Oleh karena itu, ekspresi berikut ini tidak valid:
+ `MyList[-1]`
+ `MyList[0.4]`

### Mengakses elemen peta
<a name="Expressions.Attributes.NestedElements.AccessingMapElements"></a>

Operator dereferensi untuk elemen peta adalah **.** (titik). Gunakan satu titik sebagai pemisah antara unsur-unsur dalam peta:
+ `MyMap.nestedField`
+ `MyMap.nestedField.deeplyNestedField`

## Jalur dokumen
<a name="Expressions.Attributes.NestedElements.DocumentPathExamples"></a>

Dalam sebuah ekspresi, Anda menggunakan *jalur dokumen* untuk memberi tahu DynamoDB lokasi penemuan atribut. Untuk atribut tingkat atas, jalur dokumen hanyalah nama atribut. Untuk atribut bersarang, Anda mengonstruksi jalur dokumen menggunakan operator dereferensi.

Berikut adalah beberapa contoh dari jalur dokumen. (Lihat item yang ditampilkan dalam [Mengacu pada atribut item saat menggunakan ekspresi di DynamoDB](#Expressions.Attributes).)
+ Atribut skalar tingkat atas.

   `Description`
+ Atribut daftar tingkat atas. (Ini mengembalikan seluruh daftar, bukan hanya beberapa elemen.)

  `RelatedItems`
+ Elemen ketiga dari daftar `RelatedItems`. (Ingat bahwa elemen daftar berbasis nol.)

  `RelatedItems[2]`
+ Gambar tampilan depan produk.

  `Pictures.FrontView`
+ Semua ulasan bintang lima.

  `ProductReviews.FiveStar`
+ Yang pertama dari ulasan bintang lima.

  `ProductReviews.FiveStar[0]`

**catatan**  
Kedalaman maksimum untuk jalur dokumen adalah 32. Oleh karena itu, jumlah operator dereferensi dalam suatu jalur tidak dapat melebihi batas ini.

Anda dapat menggunakan nama atribut apa pun di jalur dokumen asalkan memenuhi persyaratan berikut:
+ Karakter pertama adalah `a-z` atau `A-Z` dan atau `0-9`
+ Karakter kedua (jika ada) adalah`a-z`, `A-Z`

**catatan**  
Jika nama atribut tidak memenuhi persyaratan ini, Anda harus menentukan nama atribut ekspresi sebagai placeholder.

Untuk informasi selengkapnya, lihat [Nama atribut ekspresi (alias) di DynamoDB](Expressions.ExpressionAttributeNames.md).

# Nama atribut ekspresi (alias) di DynamoDB
<a name="Expressions.ExpressionAttributeNames"></a>

*Nama atribut ekspresi* adalah alias (atau placeholder) yang Anda gunakan dalam ekspresi Amazon DynamoDB sebagai alternatif dari nama atribut yang sebenarnya. Nama atribut ekspresi harus dimulai dengan tanda pound (`#`) dan diikuti oleh satu atau lebih karakter alfanumerik. Karakter underscore (`_`) juga diperbolehkan.

Bagian ini menjelaskan beberapa situasi ketika Anda harus menggunakan nama atribut ekspresi.

**catatan**  
Contoh di bagian ini menggunakan AWS Command Line Interface (AWS CLI). 

**Topics**
+ [Kata yang dicadangkan](#Expressions.ExpressionAttributeNames.ReservedWords)
+ [Nama atribut yang berisi karakter khusus](#Expressions.ExpressionAttributeNames.AttributeNamesContainingSpecialCharacters)
+ [Atribut bersarang](#Expressions.ExpressionAttributeNames.NestedAttributes)
+ [Berulang kali mereferensikan nama atribut](#Expressions.ExpressionAttributeNames.RepeatingAttributeNames)

## Kata yang dicadangkan
<a name="Expressions.ExpressionAttributeNames.ReservedWords"></a>

Terkadang Anda mungkin perlu menulis ekspresi yang berisi nama atribut yang bertentangan dengan kata terpesan DynamoDB. (Untuk daftar lengkap kata-kata yang dicadangkan, lihat [Kata-kata penggunaan khusus di DynamoDB](ReservedWords.md).)

Misalnya, AWS CLI contoh berikut akan gagal karena `COMMENT` merupakan kata yang dicadangkan.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "Comment"
```

Untuk mengatasi hal ini, Anda dapat mengganti `Comment` dengan nama atribut ekspresi seperti `#c`. `#` (tanda pagar) diperlukan dan menunjukkan bahwa ini adalah placeholder untuk nama atribut. AWS CLI Contohnya sekarang akan terlihat seperti berikut.

```
aws dynamodb get-item \
     --table-name ProductCatalog \
     --key '{"Id":{"N":"123"}}' \
     --projection-expression "#c" \
     --expression-attribute-names '{"#c":"Comment"}'
```

**catatan**  
Jika nama atribut dimulai dengan nomor, berisi spasi, atau berisi kata terpesan, Anda *harus* menggunakan nama atribut ekspresi untuk menggantikan nama atribut dalam ekspresi tersebut.

## Nama atribut yang berisi karakter khusus
<a name="Expressions.ExpressionAttributeNames.AttributeNamesContainingSpecialCharacters"></a>

Dalam suatu ekspresi, titik (".") ditafsirkan sebagai karakter pemisah pada jalur dokumen. Namun, DynamoDB juga memungkinkan Anda menggunakan karakter titik dan karakter khusus lainnya, seperti tanda hubung (“-”) sebagai bagian dari nama atribut. Dalam beberapa kasus, ini bisa menjadi ambigu. Untuk menggambarkan, misalkan bahwa Anda ingin mengambil atribut `Safety.Warning` dari item `ProductCatalog` (lihat [Mengacu pada atribut item saat menggunakan ekspresi di DynamoDB](Expressions.Attributes.md)).

Misalkan Anda ingin mengakses `Safety.Warning` menggunakan ekspresi proyeksi.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "Safety.Warning"
```

DynamoDB akan mengembalikan hasil kosong, bukan string yang diharapkan ("`Always wear a helmet`"). Hal ini karena DynamoDB menafsirkan titik dalam ekspresi sebagai pemisah jalur dokumen. Dalam hal ini, Anda harus menentukan nama atribut ekspresi (seperti `#sw`) sebagai pengganti untuk `Safety.Warning`. Anda kemudian dapat menggunakan ekspresi proyeksi berikut.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "#sw" \
    --expression-attribute-names '{"#sw":"Safety.Warning"}'
```

DynamoDB kemudian akan mengembalikan hasil yang benar.

**catatan**  
Jika nama atribut berisi titik (".") atau tanda hubung ("-"), Anda *harus* menggunakan nama atribut ekspresi untuk menggantikan nama atribut dalam ekspresi tersebut.

## Atribut bersarang
<a name="Expressions.ExpressionAttributeNames.NestedAttributes"></a>

Misalkan Anda ingin mengakses atribut `ProductReviews.OneStar` bersarang. Dalam nama atribut ekspresi, DynamoDB memperlakukan titik (“.”) sebagai karakter dalam nama atribut. Untuk mereferensikan atribut bersarang, tentukan nama atribut ekspresi untuk setiap elemen di jalur dokumen:
+ `#pr — ProductReviews`
+ `#1star — OneStar`

Anda kemudian dapat menggunakan `#pr.#1star` untuk ekspresi proyeksi.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "#pr.#1star"  \
    --expression-attribute-names '{"#pr":"ProductReviews", "#1star":"OneStar"}'
```

DynamoDB kemudian akan mengembalikan hasil yang benar.

## Berulang kali mereferensikan nama atribut
<a name="Expressions.ExpressionAttributeNames.RepeatingAttributeNames"></a>

Nama atribut ekspresi sangat membantu ketika Anda perlu merujuk ke nama atribut yang sama berulang-ulang. Misalnya, pertimbangkan ekspresi berikut untuk mengambil beberapa ulasan dari item `ProductCatalog`.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "ProductReviews.FiveStar, ProductReviews.ThreeStar, ProductReviews.OneStar"
```

Untuk membuat hal ini lebih jelas, Anda dapat mengganti `ProductReviews` dengan nama atribut ekspresi seperti `#pr`. Ekspresi yang direvisi kini akan terlihat seperti berikut ini.
+  `#pr.FiveStar, #pr.ThreeStar, #pr.OneStar` 

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "#pr.FiveStar, #pr.ThreeStar, #pr.OneStar" \
    --expression-attribute-names '{"#pr":"ProductReviews"}'
```

Jika Anda menentukan nama atribut ekspresi, Anda harus menggunakannya secara konsisten di seluruh ekspresi. Selain itu, Anda tidak dapat menghilangkan simbol `#`. 

# Menggunakan nilai atribut ekspresi di DynamoDB
<a name="Expressions.ExpressionAttributeValues"></a>

*Nilai atribut ekspresi* di Amazon DynamoDB bertindak sebagai variabel. Mereka adalah pengganti nilai aktual yang ingin Anda bandingkan — nilai yang mungkin tidak Anda ketahui sampai runtime. Nilai atribut ekspresi harus dimulai dengan titik dua (`:`) dan diikuti oleh satu atau beberapa karakter alfanumerik.

Misalnya, anggaplah Anda ingin menampilkan semua item `ProductCatalog` yang tersedia dalam `Black` dan berbiaya `500` atau lebih sedikit. Anda dapat menggunakan operasi `Scan` dengan ekspresi filter, seperti dalam contoh AWS Command Line Interface (AWS CLI).

```
aws dynamodb scan \
    --table-name ProductCatalog \
    --filter-expression "contains(Color, :c) and Price <= :p" \
    --expression-attribute-values file://values.json
```

Argumen untuk `--expression-attribute-values` disimpan dalam file `values.json`.

```
{
    ":c": { "S": "Black" },
    ":p": { "N": "500" }
}
```

Jika Anda menentukan nilai atribut ekspresi, Anda harus menggunakannya secara konsisten di seluruh ekspresi. Selain itu, Anda tidak dapat menghilangkan simbol `:`. 

Nilai atribut ekspresi digunakan dengan ekspresi kondisi kunci, ekspresi kondisi, ekspresi pembaruan, dan ekspresi filter.

# Menggunakan ekspresi proyeksi di DynamoDB
<a name="Expressions.ProjectionExpressions"></a>

Untuk membaca data dari tabel, Anda menggunakan operasi seperti `GetItem`, `Query`, atau `Scan`. Amazon DynamoDB mengembalikan semua atribut item secara default. Untuk mendapatkan beberapa saja, bukan semua atribut, gunakan ekspresi proyeksi.

*Ekspresi proyeksi* adalah string yang mengidentifikasi atribut yang Anda inginkan. Untuk mengambil atribut tunggal, tentukan namanya. Untuk beberapa atribut, nama harus dipisahkan koma.

Berikut adalah beberapa contoh ekspresi proyeksi, berdasarkan item `ProductCatalog` dari [Mengacu pada atribut item saat menggunakan ekspresi di DynamoDB](Expressions.Attributes.md):
+ Atribut tingkat atas tunggal.

  `Title `
+ Tiga atribut tingkat atas. DynamoDB mengambil seluruh set `Color`.

  `Title, Price, Color`
+ Empat atribut tingkat atas. DynamoDB mengembalikan seluruh konten `RelatedItems` dan `ProductReviews`.

  `Title, Description, RelatedItems, ProductReviews`

**catatan**  
Ekspresi proyeksi tidak berpengaruh pada konsumsi throughput yang disediakan. DynamoDB menentukan unit kapasitas yang dikonsumsi berdasarkan ukuran item, bukan jumlah data yang dikembalikan ke aplikasi.

**Kata-kata yang dicadangkan dan karakter khusus**

DynamoDB telah memesan kata-kata dan karakter khusus. DynamoDB memungkinkan Anda untuk menggunakan kata-kata yang dicadangkan ini dan karakter khusus untuk nama, tetapi kami menyarankan Anda menghindari melakukannya karena Anda harus menggunakan alias untuk mereka setiap kali Anda menggunakan nama-nama ini dalam sebuah ekspresi. Untuk daftar lengkap, lihat [Kata-kata penggunaan khusus di DynamoDB](ReservedWords.md).

Anda harus menggunakan nama atribut ekspresi sebagai pengganti nama sebenarnya jika: 
+ Nama atribut ada di daftar kata-kata yang dicadangkan di DynamoDB.
+ Nama atribut tidak memenuhi persyaratan bahwa karakter pertama adalah `a-z` atau `A-Z` dan bahwa karakter kedua (jika ada) adalah`a-Z`,`A-Z`, atau`0-9`.
+ Nama atribut berisi **\$1** (hash) atau**:** (titik dua).

 AWS CLI Contoh berikut menunjukkan bagaimana menggunakan ekspresi proyeksi dengan `GetItem` operasi. Ekspresi proyeksi ini mengambil atribut skalar tingkat atas (`Description`), elemen pertama dalam daftar (`RelatedItems[0]`), dan daftar bersarang dalam peta (`ProductReviews.FiveStar`).

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '"Id": { "N": "123" } \
    --projection-expression "Description, RelatedItems[0], ProductReviews.FiveStar"
```

JSON berikut akan dikembalikan untuk contoh ini.

```
{
    "Item": {
        "Description": {
            "S": "123 description"
        },
        "ProductReviews": {
            "M": {
                "FiveStar": {
                    "L": [
                        {
                            "S": "Excellent! Can't recommend it highly enough! Buy it!"
                        },
                        {
                            "S": "Do yourself a favor and buy this."
                        }
                    ]
                }
            }
        },
        "RelatedItems": {
            "L": [
                {
                    "N": "341"
                }
            ]
        }
    }
}
```

# Menggunakan ekspresi pembaruan di DynamoDB
<a name="Expressions.UpdateExpressions"></a>

Operasi `UpdateItem` memperbarui item yang sudah ada, atau menambahkan item baru ke tabel jika belum ada. Anda harus memberikan kunci item yang ingin Anda perbarui. Anda juga harus menyediakan ekspresi pembaruan, yang menunjukkan atribut yang ingin Anda ubah dan nilai yang ingin Anda tetapkan padanya. 

*Ekspresi pembaruan* menentukan cara `UpdateItem` mengubah atribut item—misalnya, menetapkan nilai skalar atau menghapus elemen dari daftar atau peta.

Berikut ini adalah ringkasan sintaksis untuk ekspresi pembaruan.

```
update-expression ::=
    [ SET action [, action] ... ]
    [ REMOVE action [, action] ...]
    [ ADD action [, action] ... ]
    [ DELETE action [, action] ...]
```

Ekspresi pembaruan terdiri dari satu atau lebih klausa. Setiap klausa dimulai dengan kata kunci `SET`, `REMOVE`, `ADD`, atau `DELETE`. Anda dapat memasukkan salah satu klausa ini dalam ekspresi pembaruan, dalam urutan apa pun. Namun, setiap kata kunci tindakan hanya dapat muncul satu kali.

Dalam setiap klausa, ada satu atau lebih tindakan yang dipisahkan dengan koma. Setiap tindakan mewakili modifikasi data.

Contoh dalam bagian ini didasarkan pada item `ProductCatalog` yang ditampilkan dalam [Menggunakan ekspresi proyeksi di DynamoDB](Expressions.ProjectionExpressions.md).

Topik di bawah ini mencakup beberapa kasus penggunaan yang berbeda untuk `SET` tindakan tersebut.

**Topics**
+ [SET — mengubah atau menambahkan atribut item](#Expressions.UpdateExpressions.SET)
+ [REMOVE—menghapus atribut dari item](#Expressions.UpdateExpressions.REMOVE)
+ [ADD — memperbarui nomor dan set](#Expressions.UpdateExpressions.ADD)
+ [DELETE — menghapus elemen dari set](#Expressions.UpdateExpressions.DELETE)
+ [Menggunakan beberapa ekspresi pembaruan](#Expressions.UpdateExpressions.Multiple)

## SET — mengubah atau menambahkan atribut item
<a name="Expressions.UpdateExpressions.SET"></a>

Gunakan tindakan `SET` dalam ekspresi pembaruan untuk menambahkan satu atau beberapa atribut ke item. Jika salah satu atribut ini sudah ada, atribut tersebut akan ditimpa dengan nilai baru. Jika Anda ingin menghindari penimpaan atribut yang ada, Anda dapat menggunakan `SET` dengan fungsi `if_not_exists`. Fungsi `if_not_exists` khusus untuk tindakan `SET` dan hanya dapat digunakan dalam ekspresi pembaruan.

Saat Anda menggunakan `SET` untuk memperbarui elemen daftar, konten elemen akan diganti dengan data baru yang Anda tentukan. Jika elemen tersebut belum ada, `SET` menambahkan elemen baru pada akhir daftar.

Jika Anda menambahkan beberapa elemen dalam satu operasi `SET`, elemen diurutkan berdasarkan nomor elemen.

Anda juga dapat menggunakan `SET` untuk menambahkan atau mengurangi dari atribut yang berjenis `Number`. Untuk melakukan beberapa tindakan `SET`, pisahkan dengan koma.

Dalam ringkasan sintaks berikut:
+ *path*Elemen adalah jalur dokumen ke item.
+ **operand**Elemen dapat berupa jalur dokumen ke item atau fungsi.

```
set-action ::=
    path = value

value ::=
    operand
    | operand '+' operand
    | operand '-' operand

operand ::=
    path | function

function ::=
    if_not_exists (path, value)
```

Jika item tidak berisi atribut di jalur yang ditentukan, `if_not_exists` evaluasi ke`value`. Kalau tidak, itu mengevaluasi. `path`

Operasi `PutItem` berikut membuat item sampel yang dirujuk oleh contoh.

```
aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json
```

Argumen untuk `--item` disimpan dalam file `item.json`. (Untuk kemudahan, hanya beberapa atribut item yang digunakan.)

```
{
    "Id": {"N": "789"},
    "ProductCategory": {"S": "Home Improvement"},
    "Price": {"N": "52"},
    "InStock": {"BOOL": true},
    "Brand": {"S": "Acme"}
}
```

**Topics**
+ [Memodifikasi atribut](#Expressions.UpdateExpressions.SET.ModifyingAttributes)
+ [Menambahkan daftar dan peta](#Expressions.UpdateExpressions.SET.AddingListsAndMaps)
+ [Menambahkan elemen ke daftar](#Expressions.UpdateExpressions.SET.AddingListElements)
+ [Menambahkan atribut peta bersarang](#Expressions.UpdateExpressions.SET.AddingNestedMapAttributes)
+ [Menambahkan dan mengurangi atribut numerik](#Expressions.UpdateExpressions.SET.IncrementAndDecrement)
+ [Melekatkan elemen ke daftar](#Expressions.UpdateExpressions.SET.UpdatingListElements)
+ [Mencegah penimpaan atribut yang ada](#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites)

### Memodifikasi atribut
<a name="Expressions.UpdateExpressions.SET.ModifyingAttributes"></a>

**Example**  
Perbarui atribut `ProductCategory` dan `Price`.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET ProductCategory = :c, Price = :p" \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
Argumen untuk `--expression-attribute-values` disimpan dalam file `values.json`.  

```
{
    ":c": { "S": "Hardware" },
    ":p": { "N": "60" }
}
```

**catatan**  
Dalam operasi `UpdateItem`, `--return-values ALL_NEW` menyebabkan DynamoDB untuk mengembalikan item seperti yang muncul setelah pembaruan.

### Menambahkan daftar dan peta
<a name="Expressions.UpdateExpressions.SET.AddingListsAndMaps"></a>

**Example**  
Tambahkan daftar baru dan peta baru.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET RelatedItems = :ri, ProductReviews = :pr" \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
Argumen untuk `--expression-attribute-values` disimpan dalam file `values.json`.  

```
{
    ":ri": {
        "L": [
            { "S": "Hammer" }
        ]
    },
    ":pr": {
        "M": {
            "FiveStar": {
                "L": [
                    { "S": "Best product ever!" }
                ]
            }
        }
    }
}
```

### Menambahkan elemen ke daftar
<a name="Expressions.UpdateExpressions.SET.AddingListElements"></a>

**Example**  
Tambahkan atribut baru ke daftar `RelatedItems`. (Ingatlah bahwa elemen daftar berbasis nol, sehingga [0] mewakili elemen pertama dalam daftar, [1] mewakili elemen kedua, dan seterusnya.)  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET RelatedItems[1] = :ri" \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
Argumen untuk `--expression-attribute-values` disimpan dalam file `values.json`.  

```
{
    ":ri": { "S": "Nails" }
}
```

**catatan**  
Saat Anda menggunakan `SET` untuk memperbarui elemen daftar, konten elemen akan diganti dengan data baru yang Anda tentukan. Jika elemen tersebut belum ada, `SET` menambahkan elemen baru pada akhir daftar.  
Jika Anda menambahkan beberapa elemen dalam satu operasi `SET`, elemen diurutkan berdasarkan nomor elemen.

### Menambahkan atribut peta bersarang
<a name="Expressions.UpdateExpressions.SET.AddingNestedMapAttributes"></a>

**Example**  
Tambahkan beberapa atribut peta bersarang.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET #pr.#5star[1] = :r5, #pr.#3star = :r3" \
    --expression-attribute-names file://names.json \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
Argumen untuk `--expression-attribute-names` disimpan dalam file `names.json`.  

```
{
    "#pr": "ProductReviews",
    "#5star": "FiveStar",
    "#3star": "ThreeStar"
}
```
Argumen untuk `--expression-attribute-values` disimpan dalam file `values.json`.  

```
{
    ":r5": { "S": "Very happy with my purchase" },
    ":r3": {
        "L": [
            { "S": "Just OK - not that great" }
        ]
    }
}
```

**penting**  
Anda tidak dapat memperbarui atribut peta bersarang jika peta induk tidak ada. Jika Anda mencoba memperbarui atribut bersarang (misalnya,`ProductReviews.FiveStar`) ketika peta induk (`ProductReviews`) tidak ada, DynamoDB mengembalikan *pesan “Jalur dokumen `ValidationException` yang disediakan dalam ekspresi pembaruan tidak valid untuk pembaruan*.”  
Saat membuat item yang akan memiliki atribut peta bersarang diperbarui nanti, inisialisasi peta kosong untuk atribut induk. Contoh:  

```
{
    "Id": {"N": "789"},
    "ProductReviews": {"M": {}},
    "Metadata": {"M": {}}
}
```
Ini memungkinkan Anda memperbarui atribut bersarang seperti `ProductReviews.FiveStar` tanpa kesalahan.

### Menambahkan dan mengurangi atribut numerik
<a name="Expressions.UpdateExpressions.SET.IncrementAndDecrement"></a>

Anda dapat menambahkan atau mengurangi dari atribut numerik yang sudah ada. Untuk melakukannya, gunakan operator `+` (plus) dan `-` (minus).

**Example**  
Kurangi `Price` dari item.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET Price = Price - :p" \
    --expression-attribute-values '{":p": {"N":"15"}}' \
    --return-values ALL_NEW
```
Untuk meningkatkan `Price`, Anda akan menggunakan operator `+` dalam ekspresi pembaruan.

### Melekatkan elemen ke daftar
<a name="Expressions.UpdateExpressions.SET.UpdatingListElements"></a>

Anda dapat menambahkan elemen ke akhir daftar. Untuk melakukannya, gunakan `SET` dengan fungsi `list_append`. (Nama fungsi ini peka huruf besar/kecil.) Fungsi `list_append` khusus untuk tindakan `SET` dan hanya dapat digunakan dalam ekspresi pembaruan. Sintaksnya adalah sebagai berikut.
+ `list_append (list1, list2)`

Fungsi ini mengambil dua daftar sebagai input dan menambahkan semua elemen dari `list2` ke ` list1`.

**Example**  
Dalam [Menambahkan elemen ke daftar](#Expressions.UpdateExpressions.SET.AddingListElements), Anda mencantumkan `RelatedItems` dan mengisinya dengan dua elemen: `Hammer` dan `Nails`. Sekarang Anda menambahkan dua elemen lagi ke akhir `RelatedItems`.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET #ri = list_append(#ri, :vals)" \
    --expression-attribute-names '{"#ri": "RelatedItems"}' \
    --expression-attribute-values file://values.json  \
    --return-values ALL_NEW
```
Argumen untuk `--expression-attribute-values` disimpan dalam file `values.json`.  

```
{
    ":vals": {
        "L": [
            { "S": "Screwdriver" },
            {"S": "Hacksaw" }
        ]
    }
}
```
Akhirnya, Anda menambahkan satu elemen lagi ke *awal* dari `RelatedItems`. Untuk melakukan hal ini, tukar urutan elemen `list_append`. (Ingatlah bahwa `list_append` mengambil dua daftar sebagai input dan menambahkan daftar kedua ke yang pertama.)  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET #ri = list_append(:vals, #ri)" \
    --expression-attribute-names '{"#ri": "RelatedItems"}' \
    --expression-attribute-values '{":vals": {"L": [ { "S": "Chisel" }]}}' \
    --return-values ALL_NEW
```
Atribut `RelatedItems` yang dihasilkan sekarang berisi lima elemen, dalam urutan berikut: `Chisel`, `Hammer`, `Nails`, `Screwdriver`, `Hacksaw`.

### Mencegah penimpaan atribut yang ada
<a name="Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites"></a>

**Example**  
Tetapkan `Price` dari suatu item, tetapi hanya jika item tersebut belum memiliki atribut `Price`. (Jika `Price` sudah ada, tidak ada yang terjadi.)  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET Price = if_not_exists(Price, :p)" \
    --expression-attribute-values '{":p": {"N": "100"}}' \
    --return-values ALL_NEW
```

## REMOVE—menghapus atribut dari item
<a name="Expressions.UpdateExpressions.REMOVE"></a>

Gunakan tindakan `REMOVE` dalam ekspresi pembaruan untuk menghapus satu atau beberapa atribut dari item di Amazon DynamoDB. Untuk melakukan beberapa tindakan `REMOVE`, pisahkan dengan koma.

Berikut ini adalah ringkasan sintaks untuk `REMOVE` dalam ekspresi pembaruan. Satu-satunya operand adalah jalur dokumen untuk atribut yang ingin Anda hapus.

```
remove-action ::=
    path
```

**Example**  
Hapus beberapa atribut dari item. (Jika atribut tidak ada, tidak ada yang terjadi.)  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "REMOVE Brand, InStock, QuantityOnHand" \
    --return-values ALL_NEW
```

### Menghapus elemen dari daftar
<a name="Expressions.UpdateExpressions.REMOVE.RemovingListElements"></a>

Anda dapat menggunakan `REMOVE` untuk menghapus elemen individu dari daftar.

**Example**  
Dalam [Melekatkan elemen ke daftar](#Expressions.UpdateExpressions.SET.UpdatingListElements), Anda mengubah atribut daftar (`RelatedItems`) sehingga berisi lima elemen:   
+ `[0]`—`Chisel`
+ `[1]`—`Hammer`
+ `[2]`—`Nails`
+ `[3]`—`Screwdriver`
+ `[4]`—`Hacksaw`
Berikut AWS Command Line Interface (AWS CLI) contoh menghapus `Hammer` dan `Nails` dari daftar.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "REMOVE RelatedItems[1], RelatedItems[2]" \
    --return-values ALL_NEW
```
Setelah `Hammer` dan `Nails` dihapus, elemen yang tersisa digeser. Daftarnya sekarang berisi hal-hal berikut:  
+ `[0]`—`Chisel`
+ `[1]`—`Screwdriver`
+ `[2]`—`Hacksaw`

## ADD — memperbarui nomor dan set
<a name="Expressions.UpdateExpressions.ADD"></a>

**catatan**  
Secara umum, kami merekomendasikan penggunaan `SET` daripada `ADD` untuk memastikan operasi idempoten.

Gunakan tindakan `ADD` dalam ekspresi pembaruan untuk menambahkan atribut baru dan nilainya untuk item.

Jika atribut sudah ada, perilaku `ADD` bergantung pada jenis daya atribut ini:
+ Jika atribut adalah angka, dan nilai yang Anda tambahkan juga angka, nilai matematis ditambahkan ke atribut yang ada. (Jika nilai adalah angka negatif, nilai tersebut dikurangi dari atribut yang ada.)
+ Jika atribut adalah suatu set, dan nilai yang Anda tambahkan juga suatu set, nilai ditambahkan ke set yang ada.

**catatan**  
Tindakan `ADD` hanya mendukung jenis daya angka dan set.

Untuk melakukan beberapa tindakan `ADD`, pisahkan dengan koma.

Dalam ringkasan sintaks berikut:
+ *path*Elemen adalah jalur dokumen ke atribut. Atribut harus berupa `Number` atau jenis daya set. 
+ *value*Elemen adalah angka yang ingin Anda tambahkan ke atribut (untuk tipe `Number` data), atau set untuk ditambahkan ke atribut (untuk jenis set).

```
add-action ::=
    path value
```

Topik di bawah ini mencakup beberapa kasus penggunaan yang berbeda untuk `ADD` tindakan tersebut.

**Topics**
+ [Menambahkan nomor](#Expressions.UpdateExpressions.ADD.Number)
+ [Menambahkan elemen ke set](#Expressions.UpdateExpressions.ADD.Set)

### Menambahkan nomor
<a name="Expressions.UpdateExpressions.ADD.Number"></a>

Anggaplah atribut `QuantityOnHand` tidak ada. AWS CLI Contoh berikut ditetapkan `QuantityOnHand` ke 5.

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "ADD QuantityOnHand :q" \
    --expression-attribute-values '{":q": {"N": "5"}}' \
    --return-values ALL_NEW
```

Kini setelah `QuantityOnHand` ada, Anda dapat menjalankan kembali contoh untuk menaikkan `QuantityOnHand` sebesar 5 setiap kali melakukannya.

### Menambahkan elemen ke set
<a name="Expressions.UpdateExpressions.ADD.Set"></a>

Anggaplah atribut `Color` tidak ada. Contoh AWS CLI berikut menetapkan `Color` untuk satu set string dengan dua elemen.

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "ADD Color :c" \
    --expression-attribute-values '{":c": {"SS":["Orange", "Purple"]}}' \
    --return-values ALL_NEW
```

Kini setelah `Color` ada, Anda dapat menambahkan lebih banyak elemen untuknya.

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "ADD Color :c" \
    --expression-attribute-values '{":c": {"SS":["Yellow", "Green", "Blue"]}}' \
    --return-values ALL_NEW
```

## DELETE — menghapus elemen dari set
<a name="Expressions.UpdateExpressions.DELETE"></a>

**penting**  
Tindakan `DELETE` hanya mendukung jenis daya `Set`.

Gunakan tindakan `DELETE` dalam ekspresi pembaruan untuk menghapus satu atau beberapa elemen dari satu set. Untuk melakukan beberapa tindakan `DELETE`, pisahkan dengan koma.

Dalam ringkasan sintaks berikut:
+ *path*Elemen adalah jalur dokumen ke atribut. Atribut harus berupa jenis daya set.
+ *subset*Ini adalah satu atau lebih elemen yang ingin Anda hapus*path*. Anda harus menentukan *subset* sebagai tipe set.

```
delete-action ::=
    path subset
```

**Example**  
Dalam [Menambahkan elemen ke set](#Expressions.UpdateExpressions.ADD.Set), Anda membuat set string `Color`. Contoh ini akan menghapus beberapa elemen dari set tersebut.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "DELETE Color :p" \
    --expression-attribute-values '{":p": {"SS": ["Yellow", "Purple"]}}' \
    --return-values ALL_NEW
```

## Menggunakan beberapa ekspresi pembaruan
<a name="Expressions.UpdateExpressions.Multiple"></a>

Anda dapat menggunakan beberapa tindakan dalam satu ekspresi pembaruan. Semua referensi atribut diselesaikan terhadap status item sebelum tindakan apa pun diterapkan.

**Example**  
Diberikan item`{"id": "1", "a": 1, "b": 2, "c": 3}`, ekspresi berikut menghapus `a` dan menggeser nilai `b` dan`c`:  

```
aws dynamodb update-item \
    --table-name test \
    --key '{"id":{"S":"1"}}' \
    --update-expression "REMOVE a SET b = a, c = b" \
    --return-values ALL_NEW
```
Hasilnya adalah`{"id": "1", "b": 1, "c": 2}`. Meskipun `a` dihapus dan `b` ditugaskan kembali dalam ekspresi yang sama, kedua referensi menyelesaikan nilai aslinya.

**Example**  
Jika Anda ingin mengubah nilai atribut dan menghapus atribut lain sepenuhnya, Anda dapat menggunakan tindakan SET dan REMOVE dalam satu pernyataan. Operasi ini akan mengurangi `Price` nilai menjadi 15 sekaligus menghapus `InStock` atribut dari item.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET Price = Price - :p REMOVE InStock" \
    --expression-attribute-values '{":p": {"N":"15"}}' \
    --return-values ALL_NEW
```

**Example**  
Jika Anda ingin menambahkan ke daftar sambil juga mengubah nilai atribut lain, Anda bisa menggunakan dua tindakan SET dalam satu pernyataan. Operasi ini akan menambahkan “Nails” ke atribut daftar `RelatedItems` dan juga menetapkan nilai `Price` ke 21.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET RelatedItems[1] = :newValue, Price = :newPrice" \
    --expression-attribute-values '{":newValue": {"S":"Nails"}, ":newPrice": {"N":"21"}}'  \
    --return-values ALL_NEW
```

# Kondisi dan filter ekspresi, operator, dan fungsi di DynamoDB
<a name="Expressions.OperatorsAndFunctions"></a>

Untuk memanipulasi data dalam tabel DynamoDB, Anda menggunakan,, dan operasi`PutItem`. `UpdateItem` `DeleteItem` Untuk operasi manipulasi data ini, Anda dapat menentukan ekspresi kondisi untuk menentukan item mana yang harus dimodifikasi. Jika ekspresi kondisi dievaluasi ke true, operasi berhasil. Jika tidak, operasi gagal.

Bagian ini mencakup fungsi dan kata kunci bawaan untuk menulis ekspresi filter dan ekspresi kondisi di Amazon DynamoDB. Untuk informasi lebih rinci mengenai fungsi dan pemrograman dengan DynamoDB, lihat [Pemrograman dengan DynamoDB dan AWS SDKs](Programming.md) dan [Referensi API DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/).

**Topics**
+ [Sintaks untuk ekspresi filter dan kondisi](#Expressions.OperatorsAndFunctions.Syntax)
+ [Membuat perbandingan](#Expressions.OperatorsAndFunctions.Comparators)
+ [Fungsi](#Expressions.OperatorsAndFunctions.Functions)
+ [Evaluasi logika](#Expressions.OperatorsAndFunctions.LogicalEvaluations)
+ [Tanda kurung](#Expressions.OperatorsAndFunctions.Parentheses)
+ [Prioritas dalam kondisi](#Expressions.OperatorsAndFunctions.Precedence)

## Sintaks untuk ekspresi filter dan kondisi
<a name="Expressions.OperatorsAndFunctions.Syntax"></a>

Dalam ringkasan sintaks berikut, *operand* dapat berupa sebagai berikut: 
+ Nama atribut tingkat atas, seperti `Id`, `Title`, `Description`, atau `ProductCategory`
+ Jalur dokumen yang mereferensikan atribut bersarang

```
condition-expression ::=
      operand comparator operand
    | operand BETWEEN operand AND operand
    | operand IN ( operand (',' operand (, ...) ))
    | function
    | condition AND condition
    | condition OR condition
    | NOT condition
    | ( condition )

comparator ::=
    =
    | <>
    | <
    | <=
    | >
    | >=

function ::=
    attribute_exists (path)
    | attribute_not_exists (path)
    | attribute_type (path, type)
    | begins_with (path, substr)
    | contains (path, operand)
    | size (path)
```

## Membuat perbandingan
<a name="Expressions.OperatorsAndFunctions.Comparators"></a>

Gunakan komparator ini untuk membandingkan operan dengan nilai tunggal:
+ `a = b`Benar jika *a* sama dengan*b*.
+ `a <> b`Benar jika *a* tidak sama dengan*b*.
+ `a < b`Benar jika *a* kurang dari*b*.
+ `a <= b`Benar jika *a* kurang dari atau sama dengan*b*.
+ `a > b`Benar jika *a* lebih besar dari*b*.
+ `a >= b`Benar jika *a* lebih besar dari atau sama dengan*b*.

Gunakan kata kunci `BETWEEN` dan `IN` untuk membandingkan operan dengan rentang nilai atau daftar nilai yang disebutkan:
+ `a BETWEEN b AND c`Benar jika *a* lebih besar dari atau sama dengan*b*, dan kurang dari atau sama dengan*c*.
+ `a IN (b, c, d) `— Benar jika *a* sama dengan nilai apa pun dalam daftar—misalnya, salah satu dari, *b**c*, atau. *d* Daftar ini dapat berisi hingga 100 nilai, dipisahkan dengan koma.

## Fungsi
<a name="Expressions.OperatorsAndFunctions.Functions"></a>

Gunakan fungsi berikut untuk menentukan apakah atribut berada dalam item, atau untuk mengevaluasi nilai atribut. Nama fungsi ini peka huruf besar/kecil. Untuk atribut bersarang, Anda harus menyediakan jalur dokumen yang lengkap.


****  

| Fungsi | Deskripsi | 
| --- | --- | 
|  `attribute_exists (path)`  | True jika item berisi atribut yang ditentukan oleh `path`. Contoh: Periksa apakah item dalam tabel `Product` memiliki tampilan tampak samping. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 
|  `attribute_not_exists (path)`  | True jika atribut yang ditentukan oleh `path` tidak ada dalam item. Contoh: Periksa apakah item memiliki atribut `Manufacturer`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 
|  `attribute_type (path, type)`  |  True jika atribut di jalur yang ditentukan merupakan jenis daya tertentu. Parameter `type` harus salah satu dari hal berikut: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Anda harus menggunakan nilai atribut ekspresi untuk parameter `type`. Contoh: Periksa apakah atribut `QuantityOnHand` berjenis Daftar. Dalam contoh ini, `:v_sub` adalah placeholder untuk string `L`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Anda harus menggunakan nilai atribut ekspresi untuk parameter `type`.   | 
|  `begins_with (path, substr)`  |  True jika atribut yang ditentukan oleh `path` dimulai dengan substring tertentu. Contoh: Periksa apakah beberapa karakter pertama dari URL gambar tampilan depan adalah `http://`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Nilai atribut ekspresi `:v_sub` adalah placeholder untuk `http://`.  | 
|  `contains (path, operand)`  | True jika atribut yang ditentukan oleh `path` adalah salah satu hal berikut: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Jika atribut yang ditentukan oleh `path` adalah `String`, `operand` harus `String`. Jika atribut yang ditentukan oleh `path` adalah `Set`, `operand` harus merupakan jenis elemen set. Jalan dan operan harus berbeda. Artinya, `contains (a, a)` mengembalikan kesalahan. Contoh: Periksa apakah atribut `Brand` berisi substring `Company`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Nilai atribut ekspresi `:v_sub` adalah placeholder untuk `Company`. Contoh: Periksa apakah produk tersedia dalam warna merah. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Nilai atribut ekspresi `:v_sub` adalah placeholder untuk `Red`. | 
|  `size (path)`  | Mengembalikan angka yang mewakili ukuran atribut ini. Berikut ini adalah jenis daya yang valid untuk digunakan dengan `size`.  Jika atribut adalah jenis `String`, `size` menampilkan panjang string. Contoh: Periksa apakah string `Brand` kurang dari atau sama dengan 20 karakter. Nilai atribut ekspresi `:v_sub` adalah placeholder untuk `20`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  Jika atribut adalah jenis `Binary`, `size` menghasilkan jumlah byte dalam nilai atribut. Contoh: Misalkan item `ProductCatalog` memiliki atribut binari yang disebut `VideoClip` yang berisi video singkat dari produk yang digunakan. Ekspresi berikut memeriksa apakah `VideoClip` melebihi 64.000 byte. Nilai atribut ekspresi `:v_sub` adalah placeholder untuk `64000`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  Jika atribut adalah jenis daya `Set`, `size` menghasilkan jumlah elemen dalam set.  Contoh: Periksa apakah produk tersedia dalam lebih dari satu warna. Nilai atribut ekspresi `:v_sub` adalah placeholder untuk `1`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  Jika atribut adalah jenis `List` atau `Map`, `size` menghasilkan jumlah elemen turunan. Contoh: Periksa apakah jumlah ulasan `OneStar` telah melampaui ambang batas tertentu. Nilai atribut ekspresi `:v_sub` adalah placeholder untuk `3`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 

## Evaluasi logika
<a name="Expressions.OperatorsAndFunctions.LogicalEvaluations"></a>

Gunakan kata kunci `AND`, `OR`, dan `NOT` untuk melakukan evaluasi logika. Dalam daftar berikut, *a* dan *b* mewakili kondisi yang akan dievaluasi.
+ `a AND b`Benar jika *a* dan *b* keduanya benar.
+ `a OR b`Benar jika salah satu *a* atau *b* (atau keduanya) benar.
+ `NOT a`Benar jika *a* salah. Salah jika *a* benar.

Berikut ini adalah contoh kode AND dalam suatu operasi.

`dynamodb-local (*)> select * from exprtest where a > 3 and a < 5;`

## Tanda kurung
<a name="Expressions.OperatorsAndFunctions.Parentheses"></a>

Gunakan tanda kurung untuk mengubah prioritas evaluasi logis. Misalnya, anggaplah bahwa kondisi *a* dan *b* benar, dan kondisi *c* itu salah. Ekspresi berikut bernilai True:
+ `a OR b AND c`

Namun, jika Anda mengapit kondisi dalam tanda kurung, kondisi tersebut akan dievaluasi terlebih dahulu. Misalnya, nilai berikut bernilai false:
+  `(a OR b) AND c`

**catatan**  
Anda dapat menyarangkan tanda kurung dalam sebuah ekspresi. Bagian paling dalam akan dievaluasi terlebih dahulu.

Berikut ini adalah contoh kode dengan tanda kurung dalam evaluasi logis.

`dynamodb-local (*)> select * from exprtest where attribute_type(b, string) or ( a = 5 and c = “coffee”);`

## Prioritas dalam kondisi
<a name="Expressions.OperatorsAndFunctions.Precedence"></a>

 DynamoDB mengevaluasi kondisi dari kiri ke kanan menggunakan aturan prioritas berikut:
+ `= <> < <= > >=`
+ `IN`
+ `BETWEEN`
+ `attribute_exists attribute_not_exists begins_with contains`
+ Tanda kurung
+ `NOT`
+ `AND`
+ `OR`

# Contoh CLI ekspresi kondisi DynamoDB
<a name="Expressions.ConditionExpressions"></a>

Berikut ini adalah beberapa AWS Command Line Interface (AWS CLI) contoh penggunaan ekspresi kondisi. Contoh-contoh ini berdasarkan tabel `ProductCatalog`, yang diperkenalkan dalam [Mengacu pada atribut item saat menggunakan ekspresi di DynamoDB](Expressions.Attributes.md). Kunci partisi untuk tabel ini adalah `Id`, dan tidak ada kunci urutan. Operasi `PutItem` berikut membuat item `ProductCatalog` sampel yang dirujuk oleh contoh.

```
aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json
```

Argumen untuk `--item` disimpan dalam file `item.json`. (Untuk kemudahan, hanya beberapa atribut item yang digunakan.)

```
{
    "Id": {"N": "456" },
    "ProductCategory": {"S": "Sporting Goods" },
    "Price": {"N": "650" }
}
```

**Topics**
+ [Put bersyarat](#Expressions.ConditionExpressions.PreventingOverwrites)
+ [Penghapusan bersyarat](#Expressions.ConditionExpressions.AdvancedComparisons)
+ [Pembaruan bersyarat](#Expressions.ConditionExpressions.SimpleComparisons)
+ [Contoh ekspresi bersyarat](#Expressions.ConditionExpressions.ConditionalExamples)

## Put bersyarat
<a name="Expressions.ConditionExpressions.PreventingOverwrites"></a>

Operasi `PutItem` menimpa item dengan kunci primer yang sama (jika ada). Jika Anda ingin menghindari hal ini, gunakan ekspresi kondisi. Hal ini memungkinkan penulisan untuk dilanjutkan hanya jika item yang dimaksud belum memiliki kunci primer yang sama.

Contoh berikut digunakan `attribute_not_exists()` untuk memeriksa apakah kunci primer ada dalam tabel sebelum mencoba operasi tulis. 

**catatan**  
Jika kunci utama Anda terdiri dari kedua kunci partisi (pk) dan kunci sortir (sk), parameter akan memeriksa apakah `attribute_not_exists(pk)` DAN `attribute_not_exists(sk)` mengevaluasi menjadi benar atau salah sebagai pernyataan keseluruhan sebelum mencoba operasi tulis.

```
aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json \
    --condition-expression "attribute_not_exists(Id)"
```

Jika ekspresi kondisi bernilai false, DynamoDB mengembalikan pesan kesalahan berikut: Permintaan bersyarat gagal.

**catatan**  
Untuk informasi selengkapnya tentang fungsi `attribute_not_exists` dan lainnya, lihat [Kondisi dan filter ekspresi, operator, dan fungsi di DynamoDB](Expressions.OperatorsAndFunctions.md).

## Penghapusan bersyarat
<a name="Expressions.ConditionExpressions.AdvancedComparisons"></a>

Untuk melakukan penghapusan bersyarat, Anda menggunakan operasi `DeleteItem` dengan ekspresi kondisi. Ekspresi kondisi harus bernilai true agar operasi berhasil; jika tidak, operasi akan gagal.

Pertimbangkan item yang didefinisikan di atas.

Misalkan Anda ingin menghapus item, tetapi hanya dalam kondisi berikut:
+  `ProductCategory` adalah "Alat Olahraga" atau "Perlengkapan Berkebun."
+  `Price` adalah antara 500 dan 600.

Contoh berikut mencoba menghapus versi item.

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"456"}}' \
    --condition-expression "(ProductCategory IN (:cat1, :cat2)) and (Price between :lo and :hi)" \
    --expression-attribute-values file://values.json
```

Argumen untuk `--expression-attribute-values` disimpan dalam file `values.json`.

```
{
    ":cat1": {"S": "Sporting Goods"},
    ":cat2": {"S": "Gardening Supplies"},
    ":lo": {"N": "500"},
    ":hi": {"N": "600"}
}
```

**catatan**  
Dalam ekspresi kondisi, `:` (karakter titik dua) menunjukkan *nilai atribut ekspresi*—placeholder untuk nilai aktual. Untuk informasi selengkapnya, lihat [Menggunakan nilai atribut ekspresi di DynamoDB](Expressions.ExpressionAttributeValues.md).  
Untuk informasi selengkapnya tentang `IN`, `AND`, dan kata kunci lainnya, lihat [Kondisi dan filter ekspresi, operator, dan fungsi di DynamoDB](Expressions.OperatorsAndFunctions.md).

Dalam contoh ini, perbandingan `ProductCategory` bernilai true, tetapi perbandingan `Price` bernilai false. Hal ini menyebabkan ekspresi kondisi untuk bernilai false dan operasi `DeleteItem` gagal.

## Pembaruan bersyarat
<a name="Expressions.ConditionExpressions.SimpleComparisons"></a>

Untuk melakukan pembaruan bersyarat, Anda menggunakan operasi `UpdateItem` dengan ekspresi kondisi. Ekspresi kondisi harus bernilai true agar operasi berhasil; jika tidak, operasi akan gagal.

**catatan**  
`UpdateItem` juga mendukung *ekspresi pembaruan*, di mana Anda menentukan modifikasi yang ingin Anda buat ke item. Untuk informasi selengkapnya, lihat [Menggunakan ekspresi pembaruan di DynamoDB](Expressions.UpdateExpressions.md).

Misalkan Anda mulai dengan item yang didefinisikan di atas.

Contoh berikut melakukan operasi `UpdateItem`. Operasi ini mencoba untuk mengurangi `Price` dari produk sebesar 75—tetapi ekspresi kondisi mencegah pembaruan jika `Price` saat ini kurang dari atau sama dengan 500.

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --update-expression "SET Price = Price - :discount" \
    --condition-expression "Price > :limit" \
    --expression-attribute-values file://values.json
```

Argumen untuk `--expression-attribute-values` disimpan dalam file `values.json`.

```
{
    ":discount": { "N": "75"},
    ":limit": {"N": "500"}
}
```

Jika `Price` awal adalah 650, operasi `UpdateItem` mengurangi `Price` menjadi 575. Jika Anda menjalankan operasi `UpdateItem` lagi, `Price` berkurang menjadi 500. Jika Anda menjalankannya untuk kali ketiga, ekspresi kondisi bernilai false, dan pembaruan gagal.

**catatan**  
Dalam ekspresi kondisi, `:` (karakter titik dua) menunjukkan *nilai atribut ekspresi*—placeholder untuk nilai aktual. Untuk informasi selengkapnya, lihat [Menggunakan nilai atribut ekspresi di DynamoDB](Expressions.ExpressionAttributeValues.md).  
Untuk informasi selengkapnya tentang "*>*" dan operator lainnya, lihat [Kondisi dan filter ekspresi, operator, dan fungsi di DynamoDB](Expressions.OperatorsAndFunctions.md).

## Contoh ekspresi bersyarat
<a name="Expressions.ConditionExpressions.ConditionalExamples"></a>

Untuk informasi selengkapnya tentang fungsi yang digunakan dalam contoh berikut, lihat [Kondisi dan filter ekspresi, operator, dan fungsi di DynamoDB](Expressions.OperatorsAndFunctions.md). Jika Anda ingin tahu lebih banyak tentang cara menentukan jenis atribut yang berbeda dalam suatu ekspresi, lihat [Mengacu pada atribut item saat menggunakan ekspresi di DynamoDB](Expressions.Attributes.md). 

### Memeriksa atribut dalam item
<a name="Expressions.ConditionExpressions.CheckingForAttributes"></a>

Anda dapat memeriksa keberadaan (atau ketiadaan) atribut apa pun. Jika ekspresi kondisi bernilai true, operasi berhasil; jika tidak, operasi akan gagal.

Contoh berikut menggunakan `attribute_not_exists` untuk menghapus produk hanya jika operasi tidak memiliki atribut `Price`.

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "attribute_not_exists(Price)"
```

DynamoDB juga menyediakan fungsi `attribute_exists`. Contoh berikut menghapus produk hanya jika operasi telah menerima ulasan buruk.

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "attribute_exists(ProductReviews.OneStar)"
```

### Memeriksa jenis atribut
<a name="Expressions.ConditionExpressions.CheckingForAttributeType"></a>

Anda dapat memeriksa jenis daya nilai atribut dengan menggunakan fungsi `attribute_type`. Jika ekspresi kondisi bernilai true, operasi berhasil; jika tidak, operasi akan gagal.

Contoh berikut menggunakan `attribute_type` untuk menghapus produk hanya jika memiliki atribut `Color` jenis Set String. 

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "attribute_type(Color, :v_sub)" \
    --expression-attribute-values file://expression-attribute-values.json
```

Argumen untuk `--expression-attribute-values` disimpan dalam expression-attribute-values file.json.

```
{
    ":v_sub":{"S":"SS"}
}
```

### Memeriksa nilai awal string
<a name="Expressions.ConditionExpressions.CheckingBeginsWith"></a>

Anda dapat memeriksa apakah nilai atribut String dimulai dengan substring tertentu dengan menggunakan fungsi `begins_with`. Jika ekspresi kondisi bernilai true, operasi berhasil; jika tidak, operasi akan gagal. 

Contoh berikut menggunakan `begins_with` untuk menghapus produk hanya jika elemen `FrontView` dari peta `Pictures` dimulai dengan nilai tertentu.

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "begins_with(Pictures.FrontView, :v_sub)" \
    --expression-attribute-values file://expression-attribute-values.json
```

Argumen untuk `--expression-attribute-values` disimpan dalam expression-attribute-values file.json.

```
{
    ":v_sub":{"S":"http://"}
}
```

### Memeriksa elemen dalam set
<a name="Expressions.ConditionExpressions.CheckingForContains"></a>

Anda dapat memeriksa elemen dalam set atau mencari substring dalam string dengan menggunakan fungsi `contains`. Jika ekspresi kondisi bernilai true, operasi berhasil; jika tidak, operasi akan gagal. 

Contoh berikut menggunakan `contains` untuk menghapus produk hanya jika elemen Set String `Color` memiliki elemen dengan nilai tertentu. 

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "contains(Color, :v_sub)" \
    --expression-attribute-values file://expression-attribute-values.json
```

Argumen untuk `--expression-attribute-values` disimpan dalam expression-attribute-values file.json.

```
{
    ":v_sub":{"S":"Red"}
}
```

### Memeriksa ukuran nilai atribut
<a name="Expressions.ConditionExpressions.CheckingForSize"></a>

Anda dapat memeriksa ukuran nilai atribut dengan menggunakan fungsi `size`. Jika ekspresi kondisi bernilai true, operasi berhasil; jika tidak, operasi akan gagal. 

Contoh berikut menggunakan `size` untuk menghapus produk hanya jika ukuran atribut Binari `VideoClip` lebih besar dari `64000` byte. 

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "size(VideoClip) > :v_sub" \
    --expression-attribute-values file://expression-attribute-values.json
```

Argumen untuk `--expression-attribute-values` disimpan dalam expression-attribute-values file.json.

```
{
    ":v_sub":{"N":"64000"}
}
```

# Menggunakan time to live (TTL) di DynamoDB
<a name="TTL"></a>

Time To Live (TTL) untuk DynamoDB adalah metode hemat biaya untuk menghapus item yang tidak lagi relevan. TTL memungkinkan Anda untuk menentukan stempel waktu kedaluwarsa per item yang menunjukkan kapan item tidak lagi diperlukan. DynamoDB secara otomatis menghapus item yang kedaluwarsa dalam beberapa hari dari waktu kedaluwarsa, tanpa menghabiskan throughput penulisan. 

Untuk menggunakan TTL, pertama-tama aktifkan pada tabel dan kemudian tentukan atribut tertentu untuk menyimpan stempel waktu kedaluwarsa TTL. Stempel waktu harus disimpan sebagai tipe data [Angka](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes) dalam [format waktu epoch Unix](https://en.wikipedia.org/wiki/Unix_time) pada perincian detik. Item dengan atribut TTL yang bukan tipe Number diabaikan oleh proses TTL. Setiap kali item dibuat atau diperbarui, Anda dapat menghitung waktu kedaluwarsa dan menyimpannya di atribut TTL.

Item dengan atribut TTL yang valid dan kedaluwarsa dapat dihapus oleh sistem kapan saja, biasanya dalam beberapa hari setelah kedaluwarsa. Anda masih dapat memperbarui item kedaluwarsa yang menunggu penghapusan, termasuk mengubah atau menghapus atribut TTL mereka. Saat memperbarui item yang kedaluwarsa, kami menyarankan Anda menggunakan ekspresi kondisi untuk memastikan item tersebut belum dihapus selanjutnya. Gunakan ekspresi filter untuk menghapus item kedaluwarsa dari hasil [Pindai](Scan.md#Scan.FilterExpression) dan [Kueri](Query.FilterExpression.md).

Item yang dihapus bekerja sama dengan yang dihapus melalui operasi penghapusan tipikal. Setelah dihapus, item masuk ke DynamoDB Streams sebagai penghapusan layanan, bukan penghapusan pengguna, dan dihapus dari indeks sekunder lokal dan indeks sekunder global seperti operasi penghapusan lainnya. 

Jika Anda menggunakan [Tabel Global versi 2019.11.21 (Saat ini)](GlobalTables.md) dari tabel global dan Anda juga menggunakan fitur TTL, DynamoDB mereplikasi penghapusan TTL ke semua tabel replika. Penghapusan TTL awal tidak menggunakan Write Capacity Units (WCU) di wilayah di mana TTL kedaluwarsa terjadi. Namun, penghapusan TTL yang direplikasi ke tabel replika menggunakan Unit Kapasitas Tulis yang direplikasi saat menggunakan kapasitas yang disediakan, atau Unit Tulis Replikasi saat menggunakan mode kapasitas sesuai permintaan, di setiap wilayah replika dan biaya yang berlaku akan berlaku.

Untuk informasi selengkapnya tentang TTL, lihat topik berikut:

**Topics**
+ [Aktifkan waktu untuk hidup (TTL) di DynamoDB](time-to-live-ttl-how-to.md)
+ [Menghitung waktu untuk hidup (TTL) di DynamoDB](time-to-live-ttl-before-you-start.md)
+ [Bekerja dengan item kedaluwarsa dan waktu untuk hidup (TTL)](ttl-expired-items.md)

# Aktifkan waktu untuk hidup (TTL) di DynamoDB
<a name="time-to-live-ttl-how-to"></a>

**catatan**  
Untuk membantu debugging dan verifikasi pengoperasian fitur TTL yang benar, nilai yang disediakan untuk item TTL dicatat dalam plaintext di log diagnostik DynamoDB.

Anda dapat mengaktifkan TTL di Amazon DynamoDB Console AWS Command Line Interface , (), atau menggunakan AWS CLI Referensi [Amazon DynamoDB API dengan salah satu yang seharusnya](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/). AWS SDKs Dibutuhkan sekitar satu jam untuk mengaktifkan TTL di semua partisi.

## Aktifkan DynamoDB TTL menggunakan konsol AWS
<a name="time-to-live-ttl-how-to-enable-console"></a>

1. Masuk ke Konsol Manajemen AWS dan buka konsol DynamoDB di. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Pilih **Tabel**, lalu pilih tabel yang ingin Anda ubah.

1. Di tab **Pengaturan tambahan**, di bagian **Time to Live (TTL)**, pilih Aktifkan untuk **mengaktifkan** TTL.

1. Saat mengaktifkan TTL pada tabel, DynamoDB mengharuskan Anda mengidentifikasi nama atribut tertentu yang akan dicari layanan saat menentukan apakah suatu item memenuhi syarat untuk kedaluwarsa. Nama atribut TTL, yang ditunjukkan di bawah ini, peka huruf besar/kecil dan harus cocok dengan atribut yang ditentukan dalam operasi baca dan tulis Anda. Ketidakcocokan akan menyebabkan item yang kedaluwarsa tidak dihapus. Mengganti nama atribut TTL mengharuskan Anda untuk menonaktifkan TTL dan kemudian mengaktifkannya kembali dengan atribut baru di masa mendatang. TTL akan terus memproses penghapusan selama kurang lebih 30 menit setelah dinonaktifkan. TTL harus dikonfigurasi ulang pada tabel yang dipulihkan.  
![\[Nama atribut TTL case-sensitive yang DynamoDB gunakan untuk menentukan kelayakan item untuk kedaluwarsa.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/EnableTTL-Settings.png)

1. (Opsional) Anda dapat melakukan tes dengan mensimulasikan tanggal dan waktu kedaluwarsa dan mencocokkan beberapa item. Ini memberi Anda daftar sampel item dan mengonfirmasi bahwa ada item yang berisi nama atribut TTL yang disediakan bersama dengan waktu kedaluwarsa.

Setelah TTL diaktifkan, atribut TTL ditandai **TTL** saat Anda melihat item di konsol DynamoDB. Anda dapat melihat tanggal dan waktu kedaluwarsa suatu item dengan mengarahkan kursor ke atribut tersebut. 

## Aktifkan DynamoDB TTL menggunakan API
<a name="time-to-live-ttl-how-to-enable-api"></a>

------
#### [ Python ]

Anda dapat mengaktifkan TTL dengan kode, menggunakan [UpdateTimeToLive](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/update_time_to_live.html)operasi.

```
import boto3


def enable_ttl(table_name, ttl_attribute_name):
    """
    Enables TTL on DynamoDB table for a given attribute name
        on success, returns a status code of 200
        on error, throws an exception

    :param table_name: Name of the DynamoDB table
    :param ttl_attribute_name: The name of the TTL attribute being provided to the table.
    """
    try:
        dynamodb = boto3.client('dynamodb')

        # Enable TTL on an existing DynamoDB table
        response = dynamodb.update_time_to_live(
            TableName=table_name,
            TimeToLiveSpecification={
                'Enabled': True,
                'AttributeName': ttl_attribute_name
            }
        )

        # In the returned response, check for a successful status code.
        if response['ResponseMetadata']['HTTPStatusCode'] == 200:
            print("TTL has been enabled successfully.")
        else:
            print(f"Failed to enable TTL, status code {response['ResponseMetadata']['HTTPStatusCode']}")
    except Exception as ex:
        print("Couldn't enable TTL in table %s. Here's why: %s" % (table_name, ex))
        raise


# your values
enable_ttl('your-table-name', 'expirationDate')
```

Anda dapat mengonfirmasi TTL diaktifkan dengan menggunakan [DescribeTimeToLive](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/describe_time_to_live.html)operasi, yang menggambarkan status TTL di atas meja. `TimeToLive`Statusnya adalah salah satu `ENABLED` atau`DISABLED`.

```
# create a DynamoDB client
dynamodb = boto3.client('dynamodb')

# set the table name
table_name = 'YourTable'

# describe TTL
response = dynamodb.describe_time_to_live(TableName=table_name)
```

------
#### [ JavaScript ]

Anda dapat mengaktifkan TTL dengan kode, menggunakan [UpdateTimeToLiveCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-dynamodb/Class/UpdateTimeToLiveCommand/)operasi.

```
import { DynamoDBClient, UpdateTimeToLiveCommand } from "@aws-sdk/client-dynamodb";

const enableTTL = async (tableName, ttlAttribute) => {

    const client = new DynamoDBClient({});

    const params = {
        TableName: tableName,
        TimeToLiveSpecification: {
            Enabled: true,
            AttributeName: ttlAttribute
        }
    };

    try {
        const response = await client.send(new UpdateTimeToLiveCommand(params));
        if (response.$metadata.httpStatusCode === 200) {
            console.log(`TTL enabled successfully for table ${tableName}, using attribute name ${ttlAttribute}.`);
        } else {
            console.log(`Failed to enable TTL for table ${tableName}, response object: ${response}`);
        }
        return response;
    } catch (e) {
        console.error(`Error enabling TTL: ${e}`);
        throw e;
    }
};

// call with your own values
enableTTL('ExampleTable', 'exampleTtlAttribute');
```

------

## Aktifkan Waktu untuk Hidup menggunakan AWS CLI
<a name="time-to-live-ttl-how-to-enable-cli-sdk"></a>

1. Aktifkan TTL pada tabel `TTLExample`.

   ```
   aws dynamodb update-time-to-live --table-name TTLExample --time-to-live-specification "Enabled=true, AttributeName=ttl"
   ```

1. Jelaskan TTL pada tabel `TTLExample`.

   ```
   aws dynamodb describe-time-to-live --table-name TTLExample
   {
       "TimeToLiveDescription": {
           "AttributeName": "ttl",
           "TimeToLiveStatus": "ENABLED"
       }
   }
   ```

1. Tambahkan item ke tabel `TTLExample` dengan atribut Waktu untuk Tayang yang diatur menggunakan shell BASH dan AWS CLI. 

   ```
   EXP=`date -d '+5 days' +%s`
   aws dynamodb put-item --table-name "TTLExample" --item '{"id": {"N": "1"}, "ttl": {"N": "'$EXP'"}}'
   ```

Contoh ini dimulai dengan tanggal saat ini dan menambahkan 5 hari untuk membuat waktu kedaluwarsa. Kemudian, contoh ini mengubah waktu kedaluwarsa menjadi format jangka waktu yang pada akhirnya menambahkan item ke "`TTLExample`". 

**catatan**  
 Salah satu cara untuk menetapkan nilai kedaluwarsa Waktu untuk Tayang adalah dengan menghitung jumlah detik yang ditambahkan ke waktu kedaluwarsa. Misalnya, 5 hari adalah 432.000 detik. Namun, seringkali lebih baik memulai dengan suatu tanggal dan bekerja dari sana.

Cukup mudah untuk mendapatkan waktu saat ini dalam format jangka waktu, seperti pada contoh berikut.
+ Terminal Linux: `date +%s`
+ Python: `import time; int(time.time())`
+ Java: `System.currentTimeMillis() / 1000L`
+ JavaScript: `Math.floor(Date.now() / 1000)`

## Aktifkan DynamoDB TTL menggunakan CloudFormation
<a name="time-to-live-ttl-how-to-enable-cf"></a>

```
AWSTemplateFormatVersion: "2010-09-09"
Resources:
  TTLExampleTable:
    Type: AWS::DynamoDB::Table
    Description: "A DynamoDB table with TTL Specification enabled"
    Properties:
      AttributeDefinitions:
        - AttributeName: "Album"
          AttributeType: "S"
        - AttributeName: "Artist"
          AttributeType: "S"
      KeySchema:
        - AttributeName: "Album"
          KeyType: "HASH"
        - AttributeName: "Artist"
          KeyType: "RANGE"
      ProvisionedThroughput:
        ReadCapacityUnits: "5"
        WriteCapacityUnits: "5"
      TimeToLiveSpecification:
        AttributeName: "TTLExampleAttribute"
        Enabled: true
```

Detail tambahan tentang penggunaan TTL dalam CloudFormation template Anda dapat ditemukan [di sini](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-table-timetolivespecification.html).

# Menghitung waktu untuk hidup (TTL) di DynamoDB
<a name="time-to-live-ttl-before-you-start"></a>

Cara umum untuk mengimplementasikan TTL adalah dengan menetapkan waktu kedaluwarsa untuk item berdasarkan kapan mereka dibuat atau terakhir diperbarui. Ini dapat dilakukan dengan menambahkan waktu ke `createdAt` dan `updatedAt` stempel waktu. Misalnya, TTL untuk item yang baru dibuat dapat diatur `createdAt` ke\$190 hari. Saat item diperbarui, TTL dapat dihitung ulang menjadi \$190 hari. `updatedAt`

Waktu kedaluwarsa yang dihitung harus dalam format epoch, dalam hitungan detik. Untuk dipertimbangkan untuk kedaluwarsa dan penghapusan, TTL tidak boleh lebih dari lima tahun yang lalu. Jika Anda menggunakan format lain, proses TTL akan mengabaikan item. Jika Anda mengatur waktu kedaluwarsa ke sometime in the future ketika Anda ingin item kedaluwarsa, item akan kedaluwarsa setelah waktu itu. Misalnya, Anda menetapkan waktu kedaluwarsa ke 1724241326 (yaitu Senin, 21 Agustus 2024 11:55:26 (UTC)). Item kedaluwarsa setelah waktu yang ditentukan. Tidak ada durasi TTL minimum. Anda dapat mengatur waktu kedaluwarsa ke waktu masa depan, seperti 5 menit dari waktu saat ini. Namun, DynamoDB biasanya menghapus item kedaluwarsa dalam waktu 48 jam setelah waktu kedaluwarsa, tidak segera ketika item kedaluwarsa.

**Topics**
+ [Buat item dan atur Waktu ke Hidup](#time-to-live-ttl-before-you-start-create)
+ [Perbarui item dan segarkan Waktu untuk Hidup](#time-to-live-ttl-before-you-start-update)

## Buat item dan atur Waktu ke Hidup
<a name="time-to-live-ttl-before-you-start-create"></a>

Contoh berikut menunjukkan bagaimana menghitung waktu kedaluwarsa saat membuat item baru, menggunakan `expireAt` sebagai nama atribut TTL. Pernyataan penugasan memperoleh waktu saat ini sebagai variabel. Dalam contoh, waktu kedaluwarsa dihitung sebagai 90 hari dari waktu saat ini. Waktu kemudian dikonversi ke format epoch dan disimpan sebagai tipe data integer dalam atribut TTL.

Contoh kode berikut menunjukkan cara membuat item dengan TTL.

------
#### [ Java ]

**SDK untuk Java 2.x**  

```
package com.amazon.samplelib.ttl;

import com.amazon.samplelib.CodeSampleUtils;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.PutItemResponse;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * Creates an item in a DynamoDB table with TTL attributes.
 * This class demonstrates how to add TTL expiration timestamps to DynamoDB items.
 */
public class CreateTTL {

    private static final String USAGE =
        """
            Usage:
                <tableName> <primaryKey> <sortKey> <region>
            Where:
                tableName - The Amazon DynamoDB table being queried.
                primaryKey - The name of the primary key. Also known as the hash or partition key.
                sortKey - The name of the sort key. Also known as the range attribute.
                region (optional) - The AWS region that the Amazon DynamoDB table is located in. (Default: us-east-1)
            """;
    private static final int DAYS_TO_EXPIRE = 90;
    private static final int SECONDS_PER_DAY = 24 * 60 * 60;
    private static final String PRIMARY_KEY_ATTR = "primaryKey";
    private static final String SORT_KEY_ATTR = "sortKey";
    private static final String CREATION_DATE_ATTR = "creationDate";
    private static final String EXPIRE_AT_ATTR = "expireAt";
    private static final String SUCCESS_MESSAGE = "%s PutItem operation with TTL successful.";
    private static final String TABLE_NOT_FOUND_ERROR = "Error: The Amazon DynamoDB table \"%s\" can't be found.";

    private final DynamoDbClient dynamoDbClient;

    /**
     * Constructs a CreateTTL instance with the specified DynamoDB client.
     *
     * @param dynamoDbClient The DynamoDB client to use
     */
    public CreateTTL(final DynamoDbClient dynamoDbClient) {
        this.dynamoDbClient = dynamoDbClient;
    }

    /**
     * Constructs a CreateTTL with a default DynamoDB client.
     */
    public CreateTTL() {
        this.dynamoDbClient = null;
    }

    /**
     * Main method to demonstrate creating an item with TTL.
     *
     * @param args Command line arguments
     */
    public static void main(final String[] args) {
        try {
            int result = new CreateTTL().processArgs(args);
            System.exit(result);
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }

    /**
     * Process command line arguments and create an item with TTL.
     *
     * @param args Command line arguments
     * @return 0 if successful, non-zero otherwise
     * @throws ResourceNotFoundException If the table doesn't exist
     * @throws DynamoDbException If an error occurs during the operation
     * @throws IllegalArgumentException If arguments are invalid
     */
    public int processArgs(final String[] args) {
        // Argument validation (remove or replace this line when reusing this code)
        CodeSampleUtils.validateArgs(args, new int[] {3, 4}, USAGE);

        final String tableName = args[0];
        final String primaryKey = args[1];
        final String sortKey = args[2];
        final Region region = Optional.ofNullable(args.length > 3 ? args[3] : null)
            .map(Region::of)
            .orElse(Region.US_EAST_1);

        try (DynamoDbClient ddb = dynamoDbClient != null
            ? dynamoDbClient
            : DynamoDbClient.builder().region(region).build()) {
            final CreateTTL createTTL = new CreateTTL(ddb);
            createTTL.createItemWithTTL(tableName, primaryKey, sortKey);
            return 0;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * Creates an item in the specified table with TTL attributes.
     *
     * @param tableName The name of the table
     * @param primaryKeyValue The value for the primary key
     * @param sortKeyValue The value for the sort key
     * @return The response from the PutItem operation
     * @throws ResourceNotFoundException If the table doesn't exist
     * @throws DynamoDbException If an error occurs during the operation
     */
    public PutItemResponse createItemWithTTL(
        final String tableName, final String primaryKeyValue, final String sortKeyValue) {
        // Get current time in epoch second format
        final long createDate = System.currentTimeMillis() / 1000;

        // Calculate expiration time 90 days from now in epoch second format
        final long expireDate = createDate + (DAYS_TO_EXPIRE * SECONDS_PER_DAY);

        final Map<String, AttributeValue> itemMap = new HashMap<>();
        itemMap.put(
            PRIMARY_KEY_ATTR, AttributeValue.builder().s(primaryKeyValue).build());
        itemMap.put(SORT_KEY_ATTR, AttributeValue.builder().s(sortKeyValue).build());
        itemMap.put(
            CREATION_DATE_ATTR,
            AttributeValue.builder().n(String.valueOf(createDate)).build());
        itemMap.put(
            EXPIRE_AT_ATTR,
            AttributeValue.builder().n(String.valueOf(expireDate)).build());

        final PutItemRequest request =
            PutItemRequest.builder().tableName(tableName).item(itemMap).build();

        try {
            final PutItemResponse response = dynamoDbClient.putItem(request);
            System.out.println(String.format(SUCCESS_MESSAGE, tableName));
            return response;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
    }
}
```
+  Untuk detail API, lihat [PutItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/PutItem)di *Referensi AWS SDK for Java 2.x API*. 

------
#### [ JavaScript ]

**SDK untuk JavaScript (v3)**  

```
import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";

export function createDynamoDBItem(table_name, region, partition_key, sort_key) {
    const client = new DynamoDBClient({
        region: region,
        endpoint: `https://dynamodb.${region}.amazonaws.com`
    });

    // Get the current time in epoch second format
    const current_time = Math.floor(new Date().getTime() / 1000);

    // Calculate the expireAt time (90 days from now) in epoch second format
    const expire_at = Math.floor((new Date().getTime() + 90 * 24 * 60 * 60 * 1000) / 1000);

    // Create DynamoDB item
    const item = {
        'partitionKey': {'S': partition_key},
        'sortKey': {'S': sort_key},
        'createdAt': {'N': current_time.toString()},
        'expireAt': {'N': expire_at.toString()}
    };

    const putItemCommand = new PutItemCommand({
        TableName: table_name,
        Item: item,
        ProvisionedThroughput: {
            ReadCapacityUnits: 1,
            WriteCapacityUnits: 1,
        },
    });

    client.send(putItemCommand, function(err, data) {
        if (err) {
            console.log("Exception encountered when creating item %s, here's what happened: ", data, err);
            throw err;
        } else {
            console.log("Item created successfully: %s.", data);
            return data;
        }
    });
}

// Example usage (commented out for testing)
// createDynamoDBItem('your-table-name', 'us-east-1', 'your-partition-key-value', 'your-sort-key-value');
```
+  Untuk detail API, lihat [PutItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/PutItemCommand)di *Referensi AWS SDK untuk JavaScript API*. 

------
#### [ Python ]

**SDK untuk Python (Boto3)**  

```
from datetime import datetime, timedelta

import boto3


def create_dynamodb_item(table_name, region, primary_key, sort_key):
    """
    Creates a DynamoDB item with an attached expiry attribute.

    :param table_name: Table name for the boto3 resource to target when creating an item
    :param region: string representing the AWS region. Example: `us-east-1`
    :param primary_key: one attribute known as the partition key.
    :param sort_key: Also known as a range attribute.
    :return: Void (nothing)
    """
    try:
        dynamodb = boto3.resource("dynamodb", region_name=region)
        table = dynamodb.Table(table_name)

        # Get the current time in epoch second format
        current_time = int(datetime.now().timestamp())

        # Calculate the expiration time (90 days from now) in epoch second format
        expiration_time = int((datetime.now() + timedelta(days=90)).timestamp())

        item = {
            "primaryKey": primary_key,
            "sortKey": sort_key,
            "creationDate": current_time,
            "expireAt": expiration_time,
        }
        response = table.put_item(Item=item)

        print("Item created successfully.")
        return response
    except Exception as e:
        print(f"Error creating item: {e}")
        raise e


# Use your own values
create_dynamodb_item(
    "your-table-name", "us-west-2", "your-partition-key-value", "your-sort-key-value"
)
```
+  Untuk detail API, lihat [PutItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/PutItem)di *AWS SDK for Python (Boto3) Referensi* API. 

------

## Perbarui item dan segarkan Waktu untuk Hidup
<a name="time-to-live-ttl-before-you-start-update"></a>

Contoh ini merupakan kelanjutan dari yang dari [bagian sebelumnya](#time-to-live-ttl-before-you-start-create). Waktu kedaluwarsa dapat dihitung ulang jika item diperbarui. Contoh berikut menghitung ulang `expireAt` stempel waktu menjadi 90 hari dari waktu saat ini.

Contoh kode berikut menunjukkan cara memperbarui TTL item.

------
#### [ Java ]

**SDK untuk Java 2.x**  
Perbarui TTL pada item DynamoDB yang ada dalam tabel.  

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemResponse;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

    public UpdateItemResponse updateItemWithTTL(
        final String tableName, final String primaryKeyValue, final String sortKeyValue) {
        // Get current time in epoch second format
        final long currentTime = System.currentTimeMillis() / 1000;

        // Calculate expiration time 90 days from now in epoch second format
        final long expireDate = currentTime + (DAYS_TO_EXPIRE * SECONDS_PER_DAY);

        // Create the key map for the item to update
        final Map<String, AttributeValue> keyMap = new HashMap<>();
        keyMap.put(PRIMARY_KEY_ATTR, AttributeValue.builder().s(primaryKeyValue).build());
        keyMap.put(SORT_KEY_ATTR, AttributeValue.builder().s(sortKeyValue).build());

        // Create the expression attribute values
        final Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
        expressionAttributeValues.put(
            ":c", AttributeValue.builder().n(String.valueOf(currentTime)).build());
        expressionAttributeValues.put(
            ":e", AttributeValue.builder().n(String.valueOf(expireDate)).build());

        final UpdateItemRequest request = UpdateItemRequest.builder()
            .tableName(tableName)
            .key(keyMap)
            .updateExpression(UPDATE_EXPRESSION)
            .expressionAttributeValues(expressionAttributeValues)
            .build();

        try {
            final UpdateItemResponse response = dynamoDbClient.updateItem(request);
            System.out.println(String.format(SUCCESS_MESSAGE, tableName));
            return response;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
    }
```
+  Untuk detail API, lihat [UpdateItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem)di *Referensi AWS SDK for Java 2.x API*. 

------
#### [ JavaScript ]

**SDK untuk JavaScript (v3)**  

```
import { DynamoDBClient, UpdateItemCommand } from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";

export const updateItem = async (tableName, partitionKey, sortKey, region = 'us-east-1') => {
    const client = new DynamoDBClient({
        region: region,
        endpoint: `https://dynamodb.${region}.amazonaws.com`
    });

    const currentTime = Math.floor(Date.now() / 1000);
    const expireAt = Math.floor((Date.now() + 90 * 24 * 60 * 60 * 1000) / 1000);

    const params = {
        TableName: tableName,
        Key: marshall({
            partitionKey: partitionKey,
            sortKey: sortKey
        }),
        UpdateExpression: "SET updatedAt = :c, expireAt = :e",
        ExpressionAttributeValues: marshall({
            ":c": currentTime,
            ":e": expireAt
        }),
    };

    try {
        const data = await client.send(new UpdateItemCommand(params));
        const responseData = unmarshall(data.Attributes);
        console.log("Item updated successfully: %s", responseData);
        return responseData;
    } catch (err) {
        console.error("Error updating item:", err);
        throw err;
    }
}

// Example usage (commented out for testing)
// updateItem('your-table-name', 'your-partition-key-value', 'your-sort-key-value');
```
+  Untuk detail API, lihat [UpdateItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/UpdateItemCommand)di *Referensi AWS SDK untuk JavaScript API*. 

------
#### [ Python ]

**SDK untuk Python (Boto3)**  

```
from datetime import datetime, timedelta

import boto3


def update_dynamodb_item(table_name, region, primary_key, sort_key):
    """
    Update an existing DynamoDB item with a TTL.
    :param table_name: Name of the DynamoDB table
    :param region: AWS Region of the table - example `us-east-1`
    :param primary_key: one attribute known as the partition key.
    :param sort_key: Also known as a range attribute.
    :return: Void (nothing)
    """
    try:
        # Create the DynamoDB resource.
        dynamodb = boto3.resource("dynamodb", region_name=region)
        table = dynamodb.Table(table_name)

        # Get the current time in epoch second format
        current_time = int(datetime.now().timestamp())

        # Calculate the expireAt time (90 days from now) in epoch second format
        expire_at = int((datetime.now() + timedelta(days=90)).timestamp())

        table.update_item(
            Key={"partitionKey": primary_key, "sortKey": sort_key},
            UpdateExpression="set updatedAt=:c, expireAt=:e",
            ExpressionAttributeValues={":c": current_time, ":e": expire_at},
        )

        print("Item updated successfully.")
    except Exception as e:
        print(f"Error updating item: {e}")


# Replace with your own values
update_dynamodb_item(
    "your-table-name", "us-west-2", "your-partition-key-value", "your-sort-key-value"
)
```
+  Untuk detail API, lihat [UpdateItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/UpdateItem)di *AWS SDK for Python (Boto3) Referensi* API. 

------

Contoh TTL yang dibahas dalam pendahuluan ini menunjukkan metode untuk memastikan hanya item yang baru diperbarui disimpan dalam tabel. Item yang diperbarui memiliki masa pakainya diperpanjang, sedangkan item yang tidak diperbarui pasca-pembuatan kedaluwarsa dan dihapus tanpa biaya, mengurangi penyimpanan dan mempertahankan tabel bersih.

# Bekerja dengan item kedaluwarsa dan waktu untuk hidup (TTL)
<a name="ttl-expired-items"></a>

Item kedaluwarsa yang tertunda penghapusan dapat difilter dari operasi baca dan tulis. Ini berguna dalam skenario ketika data kedaluwarsa tidak lagi valid dan tidak boleh digunakan. Jika tidak difilter, mereka akan terus ditampilkan dalam operasi baca dan tulis sampai dihapus oleh proses latar belakang.

**catatan**  
Barang-barang ini masih diperhitungkan untuk penyimpanan dan biaya baca sampai dihapus.

Penghapusan TTL dapat diidentifikasi di DynamoDB Streams, tetapi hanya di Wilayah tempat penghapusan terjadi. Penghapusan TTL yang direplikasi ke wilayah tabel global tidak dapat diidentifikasi dalam aliran DynamoDB di wilayah tempat penghapusan direplikasi.

## Filter item kedaluwarsa dari operasi baca
<a name="ttl-expired-items-filter"></a>

Untuk operasi baca seperti [Pindai](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html) dan [Kueri](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html), ekspresi filter dapat memfilter item kedaluwarsa yang menunggu penghapusan. Seperti yang ditunjukkan dalam cuplikan kode berikut, ekspresi filter dapat menyaring item di mana waktu TTL sama dengan atau kurang dari waktu saat ini. Misalnya, kode SDK Python menyertakan pernyataan penugasan yang memperoleh waktu saat ini sebagai variabel (`now`), dan mengubahnya menjadi format waktu epoch. `int`

Contoh kode berikut menunjukkan cara query untuk item TTL.

------
#### [ Java ]

**SDK untuk Java 2.x**  
Query Filtered Expression untuk mengumpulkan item TTL dalam tabel DynamoDB menggunakan. AWS SDK for Java 2.x  

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.QueryRequest;
import software.amazon.awssdk.services.dynamodb.model.QueryResponse;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;

import java.util.Map;
import java.util.Optional;

        final QueryRequest request = QueryRequest.builder()
            .tableName(tableName)
            .keyConditionExpression(KEY_CONDITION_EXPRESSION)
            .filterExpression(FILTER_EXPRESSION)
            .expressionAttributeNames(expressionAttributeNames)
            .expressionAttributeValues(expressionAttributeValues)
            .build();

        try (DynamoDbClient ddb = dynamoDbClient != null
            ? dynamoDbClient
            : DynamoDbClient.builder().region(region).build()) {
            final QueryResponse response = ddb.query(request);
            System.out.println("Query successful. Found " + response.count() + " items that have not expired yet.");

            // Print each item
            response.items().forEach(item -> {
                System.out.println("Item: " + item);
            });

            return 0;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
```
+  Untuk detail API, lihat [Kueri](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/Query) di *Referensi API AWS SDK for Java 2.x *. 

------
#### [ JavaScript ]

**SDK untuk JavaScript (v3)**  
Query Filtered Expression untuk mengumpulkan item TTL dalam tabel DynamoDB menggunakan. AWS SDK untuk JavaScript  

```
import { DynamoDBClient, QueryCommand } from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";

export const queryFiltered = async (tableName, primaryKey, region = 'us-east-1') => {
    const client = new DynamoDBClient({
        region: region,
        endpoint: `https://dynamodb.${region}.amazonaws.com`
    });

    const currentTime = Math.floor(Date.now() / 1000);

    const params = {
        TableName: tableName,
        KeyConditionExpression: "#pk = :pk",
        FilterExpression: "#ea > :ea",
        ExpressionAttributeNames: {
            "#pk": "primaryKey",
            "#ea": "expireAt"
        },
        ExpressionAttributeValues: marshall({
            ":pk": primaryKey,
            ":ea": currentTime
        })
    };

    try {
        const { Items } = await client.send(new QueryCommand(params));
        Items.forEach(item => {
            console.log(unmarshall(item))
        });
        return Items;
    } catch (err) {
        console.error(`Error querying items: ${err}`);
        throw err;
    }
}

// Example usage (commented out for testing)
// queryFiltered('your-table-name', 'your-partition-key-value');
```
+  Untuk detail API, lihat [Kueri](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/QueryCommand) di *Referensi API AWS SDK untuk JavaScript *. 

------
#### [ Python ]

**SDK untuk Python (Boto3)**  
Query Filtered Expression untuk mengumpulkan item TTL dalam tabel DynamoDB menggunakan. AWS SDK untuk Python (Boto3)  

```
from datetime import datetime

import boto3


def query_dynamodb_items(table_name, partition_key):
    """

    :param table_name: Name of the DynamoDB table
    :param partition_key:
    :return:
    """
    try:
        # Initialize a DynamoDB resource
        dynamodb = boto3.resource("dynamodb", region_name="us-east-1")

        # Specify your table
        table = dynamodb.Table(table_name)

        # Get the current time in epoch format
        current_time = int(datetime.now().timestamp())

        # Perform the query operation with a filter expression to exclude expired items
        # response = table.query(
        #    KeyConditionExpression=boto3.dynamodb.conditions.Key('partitionKey').eq(partition_key),
        #    FilterExpression=boto3.dynamodb.conditions.Attr('expireAt').gt(current_time)
        # )
        response = table.query(
            KeyConditionExpression=dynamodb.conditions.Key("partitionKey").eq(partition_key),
            FilterExpression=dynamodb.conditions.Attr("expireAt").gt(current_time),
        )

        # Print the items that are not expired
        for item in response["Items"]:
            print(item)

    except Exception as e:
        print(f"Error querying items: {e}")


# Call the function with your values
query_dynamodb_items("Music", "your-partition-key-value")
```
+  Untuk detail API, lihat [Kueri](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/Query) di *Referensi API AWS SDK untuk Python (Boto3)*. 

------

## Menulis secara kondisional ke item yang kedaluwarsa
<a name="ttl-expired-items-conditional-write"></a>

Ekspresi kondisi dapat digunakan untuk menghindari penulisan terhadap item yang kedaluwarsa. Cuplikan kode di bawah ini adalah pembaruan bersyarat yang memeriksa apakah waktu kedaluwarsa lebih besar dari waktu saat ini. Jika benar, operasi tulis akan berlanjut.

Contoh kode berikut menunjukkan cara memperbarui TTL item secara kondisional.

------
#### [ Java ]

**SDK untuk Java 2.x**  
Perbarui TTL pada Item DynamoDB yang ada dalam tabel, dengan kondisi.  

```
package com.amazon.samplelib.ttl;

import com.amazon.samplelib.CodeSampleUtils;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemResponse;

import java.util.Map;
import java.util.Optional;

/**
 * Updates an item in a DynamoDB table with TTL attributes using a conditional expression.
 * This class demonstrates how to conditionally update TTL expiration timestamps.
 */
public class UpdateTTLConditional {

    private static final String USAGE =
        """
            Usage:
                <tableName> <primaryKey> <sortKey> <region>
            Where:
                tableName - The Amazon DynamoDB table being queried.
                primaryKey - The name of the primary key. Also known as the hash or partition key.
                sortKey - The name of the sort key. Also known as the range attribute.
                region (optional) - The AWS region that the Amazon DynamoDB table is located in. (Default: us-east-1)
            """;
    private static final int DAYS_TO_EXPIRE = 90;
    private static final int SECONDS_PER_DAY = 24 * 60 * 60;
    private static final String PRIMARY_KEY_ATTR = "primaryKey";
    private static final String SORT_KEY_ATTR = "sortKey";
    private static final String UPDATED_AT_ATTR = "updatedAt";
    private static final String EXPIRE_AT_ATTR = "expireAt";
    private static final String UPDATE_EXPRESSION = "SET " + UPDATED_AT_ATTR + "=:c, " + EXPIRE_AT_ATTR + "=:e";
    private static final String CONDITION_EXPRESSION = "attribute_exists(" + PRIMARY_KEY_ATTR + ")";
    private static final String SUCCESS_MESSAGE = "%s UpdateItem operation with TTL successful.";
    private static final String CONDITION_FAILED_MESSAGE = "Condition check failed. Item does not exist.";
    private static final String TABLE_NOT_FOUND_ERROR = "Error: The Amazon DynamoDB table \"%s\" can't be found.";

    private final DynamoDbClient dynamoDbClient;

    /**
     * Constructs an UpdateTTLConditional with a default DynamoDB client.
     */
    public UpdateTTLConditional() {
        this.dynamoDbClient = null;
    }

    /**
     * Constructs an UpdateTTLConditional with the specified DynamoDB client.
     *
     * @param dynamoDbClient The DynamoDB client to use
     */
    public UpdateTTLConditional(final DynamoDbClient dynamoDbClient) {
        this.dynamoDbClient = dynamoDbClient;
    }

    /**
     * Main method to demonstrate conditionally updating an item with TTL.
     *
     * @param args Command line arguments
     */
    public static void main(final String[] args) {
        try {
            int result = new UpdateTTLConditional().processArgs(args);
            System.exit(result);
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }

    /**
     * Process command line arguments and conditionally update an item with TTL.
     *
     * @param args Command line arguments
     * @return 0 if successful, non-zero otherwise
     * @throws ResourceNotFoundException If the table doesn't exist
     * @throws DynamoDbException If an error occurs during the operation
     * @throws IllegalArgumentException If arguments are invalid
     */
    public int processArgs(final String[] args) {
        // Argument validation (remove or replace this line when reusing this code)
        CodeSampleUtils.validateArgs(args, new int[] {3, 4}, USAGE);

        final String tableName = args[0];
        final String primaryKey = args[1];
        final String sortKey = args[2];
        final Region region = Optional.ofNullable(args.length > 3 ? args[3] : null)
            .map(Region::of)
            .orElse(Region.US_EAST_1);

        // Get current time in epoch second format
        final long currentTime = System.currentTimeMillis() / 1000;

        // Calculate expiration time 90 days from now in epoch second format
        final long expireDate = currentTime + (DAYS_TO_EXPIRE * SECONDS_PER_DAY);

        // Create the key map for the item to update
        final Map<String, AttributeValue> keyMap = Map.of(
            PRIMARY_KEY_ATTR, AttributeValue.builder().s(primaryKey).build(),
            SORT_KEY_ATTR, AttributeValue.builder().s(sortKey).build());

        // Create the expression attribute values
        final Map<String, AttributeValue> expressionAttributeValues = Map.of(
            ":c", AttributeValue.builder().n(String.valueOf(currentTime)).build(),
            ":e", AttributeValue.builder().n(String.valueOf(expireDate)).build());

        final UpdateItemRequest request = UpdateItemRequest.builder()
            .tableName(tableName)
            .key(keyMap)
            .updateExpression(UPDATE_EXPRESSION)
            .conditionExpression(CONDITION_EXPRESSION)
            .expressionAttributeValues(expressionAttributeValues)
            .build();

        try (DynamoDbClient ddb = dynamoDbClient != null
            ? dynamoDbClient
            : DynamoDbClient.builder().region(region).build()) {
            final UpdateItemResponse response = ddb.updateItem(request);
            System.out.println(String.format(SUCCESS_MESSAGE, tableName));
            return 0;
        } catch (ConditionalCheckFailedException e) {
            System.err.println(CONDITION_FAILED_MESSAGE);
            throw e;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
    }
}
```
+  Untuk detail API, lihat [UpdateItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem)di *Referensi AWS SDK for Java 2.x API*. 

------
#### [ JavaScript ]

**SDK untuk JavaScript (v3)**  
Perbarui TTL pada Item DynamoDB yang ada dalam tabel, dengan kondisi.  

```
import { DynamoDBClient, UpdateItemCommand } from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";

export const updateItemConditional = async (tableName, partitionKey, sortKey, region = 'us-east-1', newAttribute = 'default-value') => {
    const client = new DynamoDBClient({
        region: region,
        endpoint: `https://dynamodb.${region}.amazonaws.com`
    });

    const currentTime = Math.floor(Date.now() / 1000);

    const params = {
        TableName: tableName,
        Key: marshall({
            artist: partitionKey,
            album: sortKey
        }),
        UpdateExpression: "SET newAttribute = :newAttribute",
        ConditionExpression: "expireAt > :expiration",
        ExpressionAttributeValues: marshall({
            ':newAttribute': newAttribute,
            ':expiration': currentTime
        }),
        ReturnValues: "ALL_NEW"
    };

    try {
        const response = await client.send(new UpdateItemCommand(params));
        const responseData = unmarshall(response.Attributes);
        console.log("Item updated successfully: ", responseData);
        return responseData;
    } catch (error) {
        if (error.name === "ConditionalCheckFailedException") {
            console.log("Condition check failed: Item's 'expireAt' is expired.");
        } else {
            console.error("Error updating item: ", error);
        }
        throw error;
    }
};

// Example usage (commented out for testing)
// updateItemConditional('your-table-name', 'your-partition-key-value', 'your-sort-key-value');
```
+  Untuk detail API, lihat [UpdateItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/UpdateItemCommand)di *Referensi AWS SDK untuk JavaScript API*. 

------
#### [ Python ]

**SDK untuk Python (Boto3)**  
Perbarui TTL pada Item DynamoDB yang ada dalam tabel, dengan kondisi.  

```
from datetime import datetime, timedelta

import boto3
from botocore.exceptions import ClientError


def update_dynamodb_item_ttl(table_name, region, primary_key, sort_key, ttl_attribute):
    """
    Updates an existing record in a DynamoDB table with a new or updated TTL attribute.

    :param table_name: Name of the DynamoDB table
    :param region: AWS Region of the table - example `us-east-1`
    :param primary_key: one attribute known as the partition key.
    :param sort_key: Also known as a range attribute.
    :param ttl_attribute: name of the TTL attribute in the target DynamoDB table
    :return:
    """
    try:
        dynamodb = boto3.resource("dynamodb", region_name=region)
        table = dynamodb.Table(table_name)

        # Generate updated TTL in epoch second format
        updated_expiration_time = int((datetime.now() + timedelta(days=90)).timestamp())

        # Define the update expression for adding/updating a new attribute
        update_expression = "SET newAttribute = :val1"

        # Define the condition expression for checking if 'expireAt' is not expired
        condition_expression = "expireAt > :val2"

        # Define the expression attribute values
        expression_attribute_values = {":val1": ttl_attribute, ":val2": updated_expiration_time}

        response = table.update_item(
            Key={"primaryKey": primary_key, "sortKey": sort_key},
            UpdateExpression=update_expression,
            ConditionExpression=condition_expression,
            ExpressionAttributeValues=expression_attribute_values,
        )

        print("Item updated successfully.")
        return response["ResponseMetadata"]["HTTPStatusCode"]  # Ideally a 200 OK
    except ClientError as e:
        if e.response["Error"]["Code"] == "ConditionalCheckFailedException":
            print("Condition check failed: Item's 'expireAt' is expired.")
        else:
            print(f"Error updating item: {e}")
    except Exception as e:
        print(f"Error updating item: {e}")


# replace with your values
update_dynamodb_item_ttl(
    "your-table-name",
    "us-east-1",
    "your-partition-key-value",
    "your-sort-key-value",
    "your-ttl-attribute-value",
)
```
+  Untuk detail API, lihat [UpdateItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/UpdateItem)di *AWS SDK for Python (Boto3) Referensi* API. 

------

## Mengidentifikasi item yang dihapus di DynamoDB Streams
<a name="ttl-expired-items-identifying"></a>

Catatan stream berisi bidang identitas pengguna `Records[<index>].userIdentity`. Item yang dihapus oleh proses TTL memiliki bidang berikut:

```
Records[<index>].userIdentity.type
"Service"

Records[<index>].userIdentity.principalId
"dynamodb.amazonaws.com"
```

JSON berikut menunjukkan bagian yang relevan dari catatan aliran tunggal:

```
"Records": [ 
  { 
	... 
		"userIdentity": {
		"type": "Service", 
      	"principalId": "dynamodb.amazonaws.com" 
   	} 
   ... 
	} 
]
```

# Menanyakan tabel di DynamoDB
<a name="Query"></a>

Anda dapat menggunakan operasi API `Query` di Amazon DynamoDB untuk menemukan item berdasarkan nilai kunci primer.

Anda harus memberikan nama atribut kunci partisi dan satu nilai untuk atribut tersebut. `Query` mengembalikan semua item dengan nilai kunci partisi tersebut. Secara opsional, Anda dapat memberikan atribut kunci urutan dan menggunakan operator perbandingan untuk menyaring hasil pencarian.

Untuk informasi selengkapnya tentang cara menggunakan `Query`, seperti sintaks permintaan, parameter respons, dan contoh tambahan, lihat [Kueri](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html) di *Referensi API Amazon DynamoDB*.

**Topics**
+ [Ekspresi kondisi kunci untuk operasi Query di DynamoDB](Query.KeyConditionExpressions.md)
+ [Ekspresi filter untuk operasi Query di DynamoDB](Query.FilterExpression.md)
+ [Hasil query tabel paginasi di DynamoDB](Query.Pagination.md)
+ [Aspek lain dari bekerja dengan operasi Query di DynamoDB](Query.Other.md)

# Ekspresi kondisi kunci untuk operasi Query di DynamoDB
<a name="Query.KeyConditionExpressions"></a>

Anda dapat menggunakan nama atribut apa pun dalam ekspresi kondisi kunci, asalkan karakter pertama adalah `a-z` atau `A-Z` dan karakter lainnya (mulai dari karakter kedua, jika ada) adalah `a-z`, `A-Z`, or `0-9`. Selain itu, nama atribut tidak boleh berupa kata khusus DynamoDB. (Untuk daftar lengkapnya, lihat [Kata-kata penggunaan khusus di DynamoDB](ReservedWords.md).) Jika nama atribut tidak memenuhi persyaratan ini, Anda harus menentukan nama atribut ekspresi sebagai placeholder. Untuk informasi selengkapnya, lihat [Nama atribut ekspresi (alias) di DynamoDB](Expressions.ExpressionAttributeNames.md).

Untuk item dengan nilai kunci partisi tertentu, DynamoDB menyimpan item ini berdekatan, dalam urutan berdasarkan nilai kunci urutan. Dalam operasi `Query`, DynamoDB mengambil item dalam urutan yang diurutkan, lalu memproses item menggunakan `KeyConditionExpression` dan `FilterExpression` apa pun yang mungkin ada. Baru setelah itu hasil `Query` dikirim kembali ke klien.

Operasi `Query` selalu mengembalikan kumpulan hasil. Jika tidak ditemukan item yang cocok, set hasil kosong.

Hasil `Query` selalu diurutkan berdasarkan nilai kunci urutan. Jika jenis daya kunci urutan adalah `Number`, hasilnya dikembalikan dalam urutan numerik. Jika tidak, hasilnya akan dikembalikan dalam urutan UTF-8 byte. Secara default, urutannya menaik. Untuk membalikkan urutan, atur parameter `ScanIndexForward` ke `false`.

Operasi `Query` tunggal dapat mengambil data maksimum 1 MB. Batas ini berlaku sebelum `FilterExpression` atau `ProjectionExpression` diterapkan pada hasil. Jika `LastEvaluatedKey` ada dalam respons dan bukan null, Anda harus memberi nomor halaman pada kumpulan hasil (lihat [Hasil query tabel paginasi di DynamoDB](Query.Pagination.md)).

## Contoh ekspresi kondisi kunci
<a name="Query.KeyConditionExpressions-example"></a>

Untuk menentukan kriteria pencarian, Anda menggunakan *ekspresi kondisi kunci*—string yang menentukan item yang akan dibaca dari tabel atau indeks.

Anda harus menentukan nama dan nilai kunci partisi sebagai syarat kesetaraan. Anda tidak dapat menggunakan atribut bukan kunci dalam ekspresi kondisi kunci.

Anda juga dapat memberikan kondisi kedua untuk kunci urutan (jika ada). Kondisi kunci urutan harus menggunakan salah satu operator perbandingan berikut:
+ `a = b`— true jika atribut *a* sama dengan nilai *b*
+ `a < b`— benar *a* jika kurang dari *b*
+ `a <= b`— benar jika *a* kurang dari atau sama dengan *b*
+ `a > b`Benar jika *a* lebih besar dari *b*
+ `a >= b`— benar jika *a* lebih besar dari atau sama dengan *b*
+ `a BETWEEN b AND c`— benar jika *a* lebih besar dari atau sama dengan*b*, dan kurang dari atau sama dengan*c*.

Fungsi berikut ini juga didukung:
+ `begins_with (a, substr)`— true jika nilai atribut `a` dimulai dengan substring tertentu.

Contoh berikut AWS Command Line Interface (AWS CLI) menunjukkan penggunaan ekspresi kondisi kunci. Ekspresi ini menggunakan placeholder (seperti `:name` dan `:sub`) dan bukan nilai aktual. Untuk informasi selengkapnya, lihat [Nama atribut ekspresi (alias) di DynamoDB](Expressions.ExpressionAttributeNames.md) dan [Menggunakan nilai atribut ekspresi di DynamoDB](Expressions.ExpressionAttributeValues.md).

**Example**  
Ajukan kueri tabel `Thread` untuk `ForumName` (kunci partisi) tertentu. Semua item dengan nilai `ForumName` tersebut dibaca oleh kueri karena kunci urutan (`Subject`) tidak termasuk dalam`KeyConditionExpression`.  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :name" \
    --expression-attribute-values  '{":name":{"S":"Amazon DynamoDB"}}'
```

**Example**  
Ajukan kueri tabel `Thread` untuk `ForumName` kunci partisi), tetapi kali ini hanya mengembalikan item dengan `Subject`(kunci urutan) tertentu.  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :name and Subject = :sub" \
    --expression-attribute-values  file://values.json
```
Argumen untuk `--expression-attribute-values` disimpan dalam file `values.json`.  

```
{
    ":name":{"S":"Amazon DynamoDB"},
    ":sub":{"S":"DynamoDB Thread 1"}
}
```

**Example**  
Kueri tabel `Reply` untuk `Id` tertentu (kunci partisi), tetapi hanya kembalikan item yang `ReplyDateTime` (kunci urutan) dimulai dengan karakter tertentu.  

```
aws dynamodb query \
    --table-name Reply \
    --key-condition-expression "Id = :id and begins_with(ReplyDateTime, :dt)" \
    --expression-attribute-values  file://values.json
```
Argumen untuk `--expression-attribute-values` disimpan dalam file `values.json`.  

```
{
    ":id":{"S":"Amazon DynamoDB#DynamoDB Thread 1"},
    ":dt":{"S":"2015-09"}
}
```

# Ekspresi filter untuk operasi Query di DynamoDB
<a name="Query.FilterExpression"></a>

Jika Anda perlu menyempurnakan hasil `Query` lebih lanjut, Anda dapat memberikan ekspresi filter secara opsional. *Ekspresi filter* menentukan item mana dalam hasil `Query` yang harus dikembalikan kepada Anda. Semua hasil lainnya dibuang.

Filter ekspresi diterapkan setelah `Query` selesai, namun sebelum hasilnya dikembalikan. Oleh karena itu, `Query` menggunakan jumlah kapasitas baca yang sama, terlepas dari apakah ada ekspresi filter.

Operasi `Query` dapat mengambil data maksimal 1 MB. Batasan ini berlaku sebelum ekspresi filter dievaluasi.

Filter ekspresi tidak boleh berisi atribut kunci partisi atau kunci urutan. Anda perlu menentukan atribut tersebut dalam ekspresi kondisi kunci, bukan ekspresi filter.

Sintaks untuk ekspresi filter mirip dengan ekspresi kondisi kunci. Ekspresi filter dapat menggunakan pembanding, fungsi, dan operator logika yang sama sebagai ekspresi kondisi utama. Selain itu, ekspresi filter dapat menggunakan operator tak sama dengan `<>`(), operator `OR`, operator `CONTAINS`, operator `IN`, operator `BEGINS_WITH`, operator `BETWEEN`, operator `EXISTS`, dan operator `SIZE`. Untuk informasi selengkapnya, lihat [Ekspresi kondisi kunci untuk operasi Query di DynamoDB](Query.KeyConditionExpressions.md) dan [Sintaks untuk ekspresi filter dan kondisi](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.Syntax).

**Example**  
 AWS CLI Contoh berikut query `Thread` tabel untuk tertentu `ForumName` (kunci partisi) dan `Subject` (sort key). Dari item yang ditemukan, hanya rangkaian diskusi terpopuler yang dikembalikan—dengan kata lain, hanya rangkaian diskusi yang memiliki jumlah `Views` lebih dari tertentu.  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :fn and Subject begins_with :sub" \
    --filter-expression "#v >= :num" \
    --expression-attribute-names '{"#v": "Views"}' \
    --expression-attribute-values file://values.json
```
Argumen untuk `--expression-attribute-values` disimpan dalam file `values.json`.  

```
{
    ":fn":{"S":"Amazon DynamoDB"},
    ":sub":{"S":"DynamoDB Thread 1"},
    ":num":{"N":"3"}
}
```
Perhatikan bahwa `Views` adalah kata yang dicadangkan di DynamoDB (lihat [Kata-kata penggunaan khusus di DynamoDB](ReservedWords.md)), sehingga contoh ini menggunakan `#v` sebagai placeholder. Untuk informasi selengkapnya, lihat [Nama atribut ekspresi (alias) di DynamoDB](Expressions.ExpressionAttributeNames.md).

**catatan**  
Ekspresi filter menghapus item dari set hasil `Query`. Jika memungkinkan, hindari penggunaan `Query` saat Anda ingin mengambil item dalam jumlah besar namun juga harus membuang sebagian besar item tersebut.

# Hasil query tabel paginasi di DynamoDB
<a name="Query.Pagination"></a>

DynamoDB *memberi nomor halaman* hasil dari operasi `Query`. Dengan pemberian nomor halaman, hasil `Query` dibagi menjadi "halaman" data berukuran 1 MB (atau kurang). Aplikasi bisa memproses halaman pertama hasil, lalu halaman kedua, dan seterusnya.

`Query` tunggal hanya mengembalikan set hasil yang sesuai dalam batas ukuran 1 MB. Untuk menentukan apakah terdapat lebih banyak hasil, dan untuk mengambilkan satu halaman sekaligus, aplikasi harus melakukan hal berikut: 

1. Periksa hasil `Query` tingkat rendah:
   + Jika hasilnya berisi elemen `LastEvaluatedKey` dan elemen tersebut non-null, lanjutkan ke langkah 2.
   + Jika *tidak ada* `LastEvaluatedKey` pada hasilnya, tidak ada lagi item yang dapat diambil.

1. Membangun `Query` dengan yang sama`KeyConditionExpression`. Namun, kali ini, ambil nilai `LastEvaluatedKey` dari langkah 1 dan gunakan sebagai parameter `ExclusiveStartKey` dalam permintaan `Query` baru.

1. Jalankan permintaan `Query` baru.

1. Lanjutkan ke langkah 1.

Dengan kata lain, `LastEvaluatedKey` dari respons `Query` harus digunakan sebagai `ExclusiveStartKey` untuk permintaan `Query` berikutnya. Jika tidak ada elemen `LastEvaluatedKey` dalam respons `Query`, maka Anda telah mengambil halaman hasil akhir. Jika `LastEvaluatedKey` tidak kosong, bukan berarti ada lebih banyak data di set hasil. Satu-satunya cara untuk mengetahui kapan Anda telah mencapai akhir kumpulan hasil adalah ketika `LastEvaluatedKey` kosong.

Anda dapat menggunakan AWS CLI untuk melihat perilaku ini. AWS CLI Mengirimkan `Query` permintaan tingkat rendah ke DynamoDB berulang kali, `LastEvaluatedKey` hingga tidak ada lagi dalam hasil. Perhatikan AWS CLI contoh berikut yang mengambil judul film dari tahun tertentu.

```
aws dynamodb query --table-name Movies \
    --projection-expression "title" \
    --key-condition-expression "#y = :yyyy" \
    --expression-attribute-names '{"#y":"year"}' \
    --expression-attribute-values '{":yyyy":{"N":"1993"}}' \
    --page-size 5 \
    --debug
```

Biasanya, AWS CLI menangani pagination secara otomatis. Namun, dalam contoh ini, AWS CLI `--page-size` parameter membatasi jumlah item per halaman. Parameter `--debug` mencetak informasi tingkat rendah tentang permintaan dan respons.

Jika Anda menjalankan contoh ini, respons pertama dari DynamoDB terlihat serupa dengan yang berikut ini.

```
2017-07-07 11:13:15,603 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":5,"Items":[{"title":{"S":"A Bronx Tale"}},
{"title":{"S":"A Perfect World"}},{"title":{"S":"Addams Family Values"}},
{"title":{"S":"Alive"}},{"title":{"S":"Benny & Joon"}}],
"LastEvaluatedKey":{"year":{"N":"1993"},"title":{"S":"Benny & Joon"}},
"ScannedCount":5}'
```

`LastEvaluatedKey` dalam responsnya menunjukkan bahwa tidak semua item telah diambil. AWS CLI Kemudian mengeluarkan `Query` permintaan lain ke DynamoDB. Pola permintaan dan respons ini berlanjut hingga respons akhir.

```
2017-07-07 11:13:16,291 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":1,"Items":[{"title":{"S":"What\'s Eating Gilbert Grape"}}],"ScannedCount":1}'
```

Tidak adanya `LastEvaluatedKey` menunjukkan bahwa tidak ada lagi item yang dapat diambil.

**catatan**  
 AWS SDKs Menangani respons DynamoDB tingkat rendah (termasuk ada atau tidak adanya) dan memberikan berbagai `LastEvaluatedKey` abstraksi untuk hasil paginasi. `Query` Misalnya, antarmuka dokumen SDK untuk Java menyediakan dukungan `java.util.Iterator` sehingga Anda dapat mempelajari hasilnya satu per satu.  
Untuk contoh kode dalam berbagai bahasa pemrograman, lihat [Panduan Memulai Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/) dan dokumentasi AWS SDK untuk bahasa Anda.

Anda juga dapat mengurangi ukuran halaman dengan membatasi jumlah item dalam set hasil, dengan parameter `Limit` operasi `Query`.

Untuk informasi selengkapnya tentang pembuatan kueri dengan DynamoDB, lihat [Menanyakan tabel di DynamoDB](Query.md).

# Aspek lain dari bekerja dengan operasi Query di DynamoDB
<a name="Query.Other"></a>

Bagian ini mencakup aspek tambahan dari operasi Query DynamoDB, termasuk membatasi ukuran hasil, menghitung item yang dipindai vs. dikembalikan, memantau konsumsi kapasitas baca, dan mengontrol konsistensi baca.

## Membatasi jumlah item dalam set hasil
<a name="Query.Limit"></a>

Dengan operasi `Query`, Anda dapat membatasi jumlah item yang dibaca. Untuk melakukannya, tetapkan parameter `Limit` ke jumlah maksimum item yang Anda inginkan.

Misalnya, anggaplah bahwa Anda `Query` tabel, dengan nilai `Limit` dari `6`, dan tanpa ekspresi filter. Hasil `Query` berisi enam item pertama dari tabel yang cocok dengan ekspresi kondisi kunci dari permintaan.

Sekarang anggap bahwa Anda menambahkan ekspresi filter ke `Query`. Dalam kasus ini, DynamoDB membaca hingga enam item, lalu hanya mengembalikan item yang cocok dengan ekspresi filter. Hasil `Query` akhir berisi enam item atau lebih sedikit, meskipun lebih banyak item akan cocok dengan ekspresi filter jika DynamoDB terus membaca lebih banyak item.

## Menghitung item dalam hasil
<a name="Query.Count"></a>

Selain item yang sesuai dengan kriteria Anda, respons `Query` berisi elemen berikut:
+ `ScannedCount` — Jumlah item yang cocok dengan ekspresi kondisi kunci *sebelum* ekspresi filter (jika ada) diterapkan.
+ `Count` — Jumlah item yang tersisa *setelah* ekspresi filter (jika ada) diterapkan.

**catatan**  
Jika Anda tidak menggunakan ekspresi filter, `ScannedCount` dan `Count` memiliki nilai yang sama.

Jika ukuran set hasil `Query` lebih besar dari 1 MB, `ScannedCount` dan `Count` mewakili hanya jumlah parsial dari total item. Anda harus melakukan beberapa operasi `Query` untuk mengambil semua hasil (lihat [Hasil query tabel paginasi di DynamoDB](Query.Pagination.md)).

Setiap respons `Query` berisi `ScannedCount` dan `Count` untuk item yang diproses oleh permintaan `Query` khusus. Untuk mendapatkan total keseluruhan untuk semua permintaan `Query`, Anda dapat menyimpan penghitungan `ScannedCount` dan `Count`.

## Unit kapasitas yang digunakan oleh kueri
<a name="Query.CapacityUnits"></a>

Anda dapat melakukan `Query` tabel atau indeks sekunder apa pun, selama Anda memberikan nama atribut kunci partisi dan satu nilai untuk atribut tersebut. `Query` mengembalikan semua item dengan nilai kunci partisi tersebut. Secara opsional, Anda dapat memberikan atribut kunci urutan dan menggunakan operator perbandingan untuk menyaring hasil pencarian. `Query` Operasi API menggunakan unit kapasitas baca, sebagai berikut.


****  

| Jika Anda `Query`... | DynamoDB menggunakan unit kapasitas baca dari... | 
| --- | --- | 
| Tabel | Kapasitas baca yang ditetapkan tabel. | 
| Indeks sekunder global | Kapasitas baca yang ditetapkan indeks. | 
| Indeks sekunder lokal | Kapasitas baca yang ditetapkan tabel dasar. | 

Secara default, operasi `Query` tidak menampilkan data tentang berapa banyak kapasitas baca yang digunakan. Namun, Anda dapat menentukan parameter `ReturnConsumedCapacity` dalam sebuah permintaan `Query` untuk mendapatkan informasi ini. Berikut ini adalah pengaturan yang valid untuk `ReturnConsumedCapacity`:
+ `NONE` — Tidak ada penggunaan data kapasitas yang ditampilkan. (Ini menjadi opsi default.)
+ `TOTAL` — Respons mencakup jumlah agregat unit kapasitas baca yang digunakan.
+ `INDEXES` — Respons menunjukkan jumlah agregat unit kapasitas baca yang digunakan, beserta dengan kapasitas yang digunakan untuk setiap tabel dan indeks yang diakses.

DynamoDB menghitung jumlah unit kapasitas baca yang dikonsumsi berdasarkan jumlah item dan ukuran item tersebut, bukan pada jumlah data yang dikembalikan ke aplikasi. Dengan alasan ini, jumlah unit kapasitas yang digunakan adalah sama, entah Anda meminta semua atribut (perilaku default) atau hanya beberapa dari atribut tersebut (menggunakan ekspresi proyeksi). Jumlahnya juga sama apakah Anda menggunakan ekspresi filter atau tidak. `Query`mengkonsumsi unit kapasitas baca minimum untuk melakukan satu pembacaan yang sangat konsisten per detik, atau dua pembacaan yang konsisten per detik untuk item hingga 4 KB. Jika Anda perlu membaca item yang lebih besar dari 4 KB, DynamoDB memerlukan unit permintaan baca tambahan. Tabel kosong dan tabel yang sangat besar yang memiliki jumlah kunci partisi yang jarang mungkin melihat beberapa tambahan RCUs dibebankan di luar jumlah data yang ditanyakan. Ini mencakup biaya melayani `Query` permintaan, bahkan jika tidak ada data.

## Konsistensi baca untuk kueri
<a name="Query.ReadConsistency"></a>

Operasi `Query` melakukan bacaan akhir konsisten, secara default. Ini berarti bahwa hasil `Query` mungkin tidak mencerminkan perubahan karena operasi `PutItem` atau `UpdateItem` baru saja selesai. Untuk informasi selengkapnya, lihat [DynamoDB membaca konsistensi](HowItWorks.ReadConsistency.md).

Jika Anda memerlukan bacaan sangat konsisten, atur parameter `ConsistentRead` ke `true` dalam permintaan `Query`.

# Memindai tabel di DynamoDB
<a name="Scan"></a>

Operasi `Scan` di Amazon DynamoDB membaca setiap item dalam tabel atau indeks sekunder. Secara default, operasi `Scan` mengembalikan semua atribut data untuk setiap item dalam tabel atau indeks. Anda dapat menggunakan parameter `ProjectionExpression` sehingga `Scan` hanya mengembalikan beberapa atribut, bukan semuanya.

`Scan` selalu mengembalikan set hasil. Jika tidak ditemukan item yang cocok, set hasil kosong.

Permintaan `Scan` tunggal dapat mengambil data maksimum 1 MB. Atau, DynamoDB dapat menerapkan ekspresi filter pada data ini, mengerucutkan hasil sebelum dikembalikan ke pengguna.

**Topics**
+ [Ekspresi filter untuk pemindaian](#Scan.FilterExpression)
+ [Membatasi jumlah item dalam set hasil](#Scan.Limit)
+ [Memberi nomor halaman hasil](#Scan.Pagination)
+ [Menghitung item dalam hasil](#Scan.Count)
+ [Unit kapasitas dikonsumsi oleh pemindaian](#Scan.CapacityUnits)
+ [Konsistensi baca untuk kueri](#Scan.ReadConsistency)
+ [Pemindaian paralel](#Scan.ParallelScan)

## Ekspresi filter untuk pemindaian
<a name="Scan.FilterExpression"></a>

Jika Anda perlu menyempurnakan hasil `Scan` lebih lanjut, Anda dapat memberikan ekspresi filter secara opsional. *Ekspresi filter* menentukan item mana dalam hasil `Scan` yang harus dikembalikan kepada Anda. Semua hasil lainnya dibuang.

Filter ekspresi diterapkan setelah `Scan` selesai, tetapi sebelum hasilnya dikembalikan. Oleh karena itu, `Scan` menggunakan jumlah kapasitas baca yang sama, terlepas dari apakah ada ekspresi filter.

Operasi `Scan` dapat mengambil data maksimal 1 MB. Batasan ini berlaku sebelum ekspresi filter dievaluasi.

Dengan `Scan`, Anda dapat menentukan atribut apa pun dalam ekspresi filter, termasuk atribut kunci partisi dan kunci urutan.

Sintaks untuk ekspresi filter mirip dengan ekspresi kondisi kunci. Ekspresi filter dapat menggunakan pembanding, fungsi, dan operator logika yang sama sebagai ekspresi kondisi utama. Lihat [Kondisi dan filter ekspresi, operator, dan fungsi di DynamoDB](Expressions.OperatorsAndFunctions.md) untuk informasi selengkapnya tentang operator logika.

**Example**  
Contoh berikut AWS Command Line Interface (AWS CLI) memindai `Thread` tabel dan hanya mengembalikan item yang terakhir diposting oleh pengguna tertentu.  

```
aws dynamodb scan \
     --table-name Thread \
     --filter-expression "LastPostedBy = :name" \
     --expression-attribute-values '{":name":{"S":"User A"}}'
```

## Membatasi jumlah item dalam set hasil
<a name="Scan.Limit"></a>

Operasi `Scan` memungkinkan Anda membatasi jumlah item yang dikembalikan dalam hasil. Untuk melakukannya, tetapkan parameter `Limit` pada jumlah maksimum item yang Anda inginkan untuk dikembalikan operasi `Scan`, sebelum evaluasi ekspresi filter.

Misalnya, anggaplah bahwa Anda melakukan `Scan` pada tabel, dengan nilai `Limit` adalah `6`, dan tanpa ekspresi filter. Hasil `Scan` berisi enam item pertama dari tabel.

Sekarang anggap bahwa Anda menambahkan ekspresi filter ke `Scan`. Dalam kasus ini, DynamoDB menerapkan ekspresi filter untuk enam item yang dikembalikan, membuang item yang tidak cocok. Hasil `Scan` akhir berisi enam item atau lebih sedikit, tergantung jumlah item yang disaring.

## Memberi nomor halaman hasil
<a name="Scan.Pagination"></a>

DynamoDB *memberi nomor halaman* hasil dari operasi `Scan`. Dengan pemberian nomor halaman, hasil `Scan` dibagi menjadi "halaman" data berukuran 1 MB (atau kurang). Aplikasi bisa memproses halaman pertama hasil, lalu halaman kedua, dan seterusnya.

`Scan` tunggal hanya mengembalikan set hasil yang sesuai dalam batas ukuran 1 MB. 

Untuk menentukan apakah terdapat lebih banyak hasil, dan untuk mengambilkan satu halaman sekaligus, aplikasi harus melakukan hal berikut:

1. Periksa hasil `Scan` tingkat rendah:
   + Jika hasilnya berisi elemen `LastEvaluatedKey`, lanjutkan ke langkah 2.
   + Jika *tidak ada* `LastEvaluatedKey` pada hasilnya, tidak ada lagi item yang dapat diambil.

1. Buat permintaan `Scan` baru, dengan parameter yang sama seperti yang sebelumnya. Namun, kali ini, ambil nilai `LastEvaluatedKey` dari langkah 1 dan gunakan sebagai parameter `ExclusiveStartKey` dalam permintaan `Scan` baru.

1. Jalankan permintaan `Scan` baru.

1. Lanjutkan ke langkah 1.

Dengan kata lain, `LastEvaluatedKey` dari respons `Scan` harus digunakan sebagai `ExclusiveStartKey` untuk permintaan `Scan` berikutnya. Jika tidak ada elemen `LastEvaluatedKey` dalam respons `Scan`, Anda telah mengambil halaman hasil akhir. (Tidak adanya `LastEvaluatedKey` adalah satu-satunya cara untuk mengetahui bahwa Anda telah mencapai akhir set hasil.)

Anda dapat menggunakan AWS CLI untuk melihat perilaku ini. AWS CLI Mengirimkan `Scan` permintaan tingkat rendah ke DynamoDB, berulang kali, `LastEvaluatedKey` hingga tidak lagi hadir dalam hasil. Perhatikan AWS CLI contoh berikut yang memindai seluruh `Movies` tabel tetapi hanya mengembalikan film dari genre tertentu.

```
aws dynamodb scan \
    --table-name Movies \
    --projection-expression "title" \
    --filter-expression 'contains(info.genres,:gen)' \
    --expression-attribute-values '{":gen":{"S":"Sci-Fi"}}' \
    --page-size 100  \
    --debug
```

Biasanya, AWS CLI menangani pagination secara otomatis. Namun, dalam contoh ini, AWS CLI `--page-size` parameter membatasi jumlah item per halaman. Parameter `--debug` mencetak informasi tingkat rendah tentang permintaan dan respons.

**catatan**  
Hasil pemberian nomor halaman Anda juga akan berbeda berdasarkan parameter input yang Anda lewati.   
Menggunakan `aws dynamodb scan --table-name Prices --max-items 1` mengembalikan `NextToken`
Menggunakan `aws dynamodb scan --table-name Prices --limit 1` mengembalikan `LastEvaluatedKey`.
Ketahuilah juga bahwa menggunakan `--starting-token` khususnya membutuhkan nilai `NextToken`. 

Jika Anda menjalankan contoh ini, respons pertama dari DynamoDB terlihat serupa dengan yang berikut ini.

```
2017-07-07 12:19:14,389 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":7,"Items":[{"title":{"S":"Monster on the Campus"}},{"title":{"S":"+1"}},
{"title":{"S":"100 Degrees Below Zero"}},{"title":{"S":"About Time"}},{"title":{"S":"After Earth"}},
{"title":{"S":"Age of Dinosaurs"}},{"title":{"S":"Cloudy with a Chance of Meatballs 2"}}],
"LastEvaluatedKey":{"year":{"N":"2013"},"title":{"S":"Curse of Chucky"}},"ScannedCount":100}'
```

`LastEvaluatedKey` dalam responsnya menunjukkan bahwa tidak semua item telah diambil. AWS CLI Kemudian mengeluarkan `Scan` permintaan lain ke DynamoDB. Pola permintaan dan respons ini berlanjut hingga respons akhir.

```
2017-07-07 12:19:17,830 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":1,"Items":[{"title":{"S":"WarGames"}}],"ScannedCount":6}'
```

Tidak adanya `LastEvaluatedKey` menunjukkan bahwa tidak ada lagi item yang dapat diambil.

**catatan**  
 AWS SDKs Menangani respons DynamoDB tingkat rendah (termasuk ada atau tidak adanya) dan memberikan berbagai `LastEvaluatedKey` abstraksi untuk hasil paginasi. `Scan` Misalnya, antarmuka dokumen SDK untuk Java menyediakan dukungan `java.util.Iterator` sehingga Anda dapat mempelajari hasilnya satu per satu.  
Untuk contoh kode dalam berbagai bahasa pemrograman, lihat [Panduan Memulai Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/) dan dokumentasi AWS SDK untuk bahasa Anda.

## Menghitung item dalam hasil
<a name="Scan.Count"></a>

Selain item yang sesuai dengan kriteria Anda, respons `Scan` berisi elemen berikut:
+ `ScannedCount` — Jumlah item yang dievaluasi, sebelum `ScanFilter` diterapkan. Nilai `ScannedCount` yang tinggi dengan sedikit, atau tanpa hasil, `Count` hasil menunjukkan operasi `Scan` yang tidak efisien. Jika Anda tidak menggunakan filter dalam permintaan, `ScannedCount` sama dengan `Count`. 
+ `Count` — Jumlah item yang tersisa *setelah* ekspresi filter (jika ada) diterapkan.

**catatan**  
Jika Anda tidak menggunakan ekspresi filter, `ScannedCount` dan `Count` memiliki nilai yang sama.

Jika ukuran set hasil `Scan` lebih besar dari 1 MB, `ScannedCount` dan `Count` mewakili hanya jumlah parsial dari total item. Anda harus melakukan beberapa operasi `Scan` untuk mengambil semua hasil (lihat [Memberi nomor halaman hasil](#Scan.Pagination)).

Setiap respons `Scan` berisi `ScannedCount` dan `Count` untuk item yang diproses oleh permintaan `Scan` khusus. Untuk mendapatkan total keseluruhan untuk semua permintaan `Scan`, Anda dapat menyimpan penghitungan `ScannedCount` dan `Count`.

## Unit kapasitas dikonsumsi oleh pemindaian
<a name="Scan.CapacityUnits"></a>

Anda dapat melakukan `Scan` pada setiap tabel atau indeks sekunder. Operasi `Scan` mengonsumsi unit kapasitas baca, sebagai berikut.


****  

| Jika Anda `Scan`... | DynamoDB menggunakan unit kapasitas baca dari... | 
| --- | --- | 
| Tabel | Kapasitas baca yang ditetapkan tabel. | 
| Indeks sekunder global | Kapasitas baca yang ditetapkan indeks. | 
| Indeks sekunder lokal | Kapasitas baca yang ditetapkan tabel dasar. | 

**catatan**  
Akses lintas akun untuk operasi pemindaian indeks sekunder saat ini tidak didukung dengan kebijakan berbasis [sumber daya](access-control-resource-based.md).

Secara default, operasi `Scan` tidak menampilkan data tentang berapa banyak kapasitas baca yang digunakan. Namun, Anda dapat menentukan parameter `ReturnConsumedCapacity` dalam sebuah permintaan `Scan` untuk mendapatkan informasi ini. Berikut ini adalah pengaturan yang valid untuk `ReturnConsumedCapacity`:
+ `NONE` — Tidak ada penggunaan data kapasitas yang ditampilkan. (Ini menjadi opsi default.)
+ `TOTAL` — Respons mencakup jumlah agregat unit kapasitas baca yang digunakan.
+ `INDEXES` — Respons menunjukkan jumlah agregat unit kapasitas baca yang digunakan, beserta dengan kapasitas yang digunakan untuk setiap tabel dan indeks yang diakses.

DynamoDB menghitung jumlah unit kapasitas baca yang dikonsumsi berdasarkan jumlah item dan ukuran item tersebut, bukan pada jumlah data yang dikembalikan ke aplikasi. Dengan alasan ini, jumlah unit kapasitas yang digunakan adalah sama, entah Anda meminta semua atribut (perilaku default) atau hanya beberapa dari atribut tersebut (menggunakan ekspresi proyeksi). Jumlahnya juga sama apakah Anda menggunakan ekspresi filter atau tidak. `Scan`mengkonsumsi unit kapasitas baca minimum untuk melakukan satu pembacaan yang sangat konsisten per detik, atau dua pembacaan yang konsisten per detik untuk item hingga 4 KB. Jika Anda perlu membaca item yang lebih besar dari 4 KB, DynamoDB memerlukan unit permintaan baca tambahan. Tabel kosong dan tabel yang sangat besar yang memiliki jumlah kunci partisi yang jarang mungkin melihat beberapa tambahan yang RCUs dibebankan melebihi jumlah data yang dipindai. Ini mencakup biaya melayani `Scan` permintaan, bahkan jika tidak ada data.

## Konsistensi baca untuk kueri
<a name="Scan.ReadConsistency"></a>

Operasi `Scan` melakukan bacaan akhir konsisten, secara default. Ini berarti bahwa hasil `Scan` mungkin tidak mencerminkan perubahan karena operasi `PutItem` atau `UpdateItem` baru saja selesai. Untuk informasi selengkapnya, lihat [DynamoDB membaca konsistensi](HowItWorks.ReadConsistency.md).

Jika Anda memerlukan bacaan sangat konsisten, pada saat `Scan` dimulai, atur parameter `ConsistentRead` menjadi `true` dalam permintaan `Scan`. Hal ini memastikan bahwa semua operasi tulis yang diselesaikan sebelum `Scan` dimulai termasuk dalam respons `Scan`. 

Mengatur `ConsistentRead` ke `true` dapat berguna dalam skenario pencadangan atau replikasi tabel, dalam hubungannya dengan [DynamoDB Streams](./Streams.html). Anda pertama kali menggunakan `Scan` dengan `ConsistentRead` yang diatur ke true untuk mendapatkan salinan data yang konsisten dalam tabel. Selama `Scan`, DynamoDB Streams mencatat aktivitas tulis tambahan yang terjadi pada tabel. Setelah `Scan` selesai, Anda dapat menerapkan aktivitas tulis dari stream ke table.

**catatan**  
Operasi `Scan` dengan `ConsistentRead` yang diatue ke `true` mengonsumsi dua kali lebih banyak unit kapasitas baca dibandingkan dengan meninggalkan `ConsistentRead` pada nilai defaultnya (`false`).

## Pemindaian paralel
<a name="Scan.ParallelScan"></a>

Secara default, operasi `Scan` memproses data secara berurutan. Amazon DynamoDB mengembalikan data ke aplikasi dalam kenaikan 1 MB, dan aplikasi melakukan operasi `Scan` tambahan untuk mengambil 1 MB data berikutnya. 

Makin besar tabel atau indeks yang dipindai, makin banyak waktu yang diperlukan untuk menyelesaikan `Scan`. Selain itu, `Scan` berurutan mungkin tidak selalu dapat sepenuhnya menggunakan kapasitas throughput baca yang disediakan: Meskipun DynamoDB mendistribusikan data tabel besar ke beberapa partisi fisik, operasi `Scan` hanya dapat membaca satu partisi dalam satu waktu. Karena alasan ini, throughput `Scan` dibatasi oleh throughput maksimum dari satu partisi.

Untuk mengatasi masalah ini, operasi `Scan` dapat secara logis membagi tabel atau indeks sekunder menjadi beberapa *segmen*, dengan beberapa pekerja aplikasi memindai segmen tersebut secara paralel. Setiap pekerja dapat berupa thread (dalam bahasa pemrograman yang mendukung multithreading) atau proses sistem operasi. Untuk melakukan pemindaian paralel, setiap pekerja mengeluarkan permintaan `Scan`-nya sendiri dengan parameter berikut:
+ `Segment` — Segmen yang akan dipindai oleh pekerja tertentu. Setiap pekerja harus menggunakan nilai yang berbeda untuk `Segment`.
+ `TotalSegments` — Jumlah total segmen untuk pemindaian paralel. Nilai ini harus sama dengan jumlah pekerja yang akan digunakan aplikasi Anda.

Diagram berikut menunjukkan bagaimana aplikasi multithreaded melakukan `Scan` paralel dengan tiga derajat paralelisme.

![\[Aplikasi multithreaded yang melakukan pemindaian paralel dengan membagi tabel menjadi tiga segmen.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/ParallelScan.png)




Dalam diagram ini, aplikasi memunculkan tiga thread dan memberikan angka pada setiap thread. (Segmen berbasis nol, sehingga angka pertama selalu 0.) Setiap thread menerbitkan permintaan `Scan`, mengatur `Segment` ke angka yang ditunjuk dan mengatur `TotalSegments` ke 3. Setiap thread memindai segmen yang ditunjuk, mengambil data 1 MB pada satu waktu, dan mengembalikan data ke thread utama aplikasi.

DynamoDB menetapkan item *ke* segmen dengan menerapkan fungsi hash ke kunci partisi setiap item. Untuk `TotalSegments` nilai yang diberikan, semua item dengan kunci partisi yang sama selalu ditetapkan untuk yang sama`Segment`. Ini berarti bahwa dalam tabel di mana *Item 1*, *Item 2*, dan *Item 3* semuanya berbagi `pk="account#123"` (tetapi memiliki kunci pengurutan yang berbeda), item ini akan diproses oleh pekerja yang sama, terlepas dari nilai kunci pengurutan atau ukuran *koleksi item*.

Karena penetapan *segmen* hanya didasarkan pada hash kunci partisi, segmen dapat didistribusikan secara tidak merata. Beberapa segmen mungkin tidak berisi item, sementara yang lain mungkin berisi banyak kunci partisi dengan koleksi item besar. Akibatnya, peningkatan jumlah segmen tidak menjamin kinerja pemindaian yang lebih cepat, terutama ketika kunci partisi tidak didistribusikan secara merata di seluruh ruang kunci.

Nilai untuk `Segment` dan `TotalSegments` diterapkan untuk permintaan `Scan` individual, dan Anda dapat menggunakan nilai yang berbeda setiap saat. Anda mungkin perlu bereksperimen dengan nilai-nilai ini, dan jumlah pekerja yang Anda gunakan, sampai aplikasi Anda mencapai performa terbaiknya.

**catatan**  
Pemindaian paralel dengan sejumlah besar pekerja dapat dengan mudah menggunakan semua throughput yang disediakan untuk tabel atau indeks yang sedang dipindai. Sebaiknya hindari pemindaian seperti itu jika tabel atau indeks juga mengalami aktivitas baca atau tulis yang berat dari aplikasi lain.  
Untuk mengontrol jumlah data yang dikembalikan per permintaan, gunakan parameter `Limit`. Hal ini dapat membantu mencegah situasi di mana satu pekerja mengkonsumsi semua throughput yang ditetapkan, dengan mengorbankan semua pekerja lainnya.

# PartiQL - Bahasa kueri yang kompatibel dengan SQL untuk Amazon DynamoDB
<a name="ql-reference"></a>

Amazon DynamoDB mendukung [PartiQL](https://partiql.org/), bahasa kueri yang kompatibel dengan SQL untuk memilih, menyisipkan, memperbarui, dan menghapus data di Amazon DynamoDB. Menggunakan PartiQL, Anda dapat dengan mudah berinteraksi dengan tabel DynamoDB dan menjalankan kueri ad hoc menggunakan, Konsol Manajemen AWS NoSQL Workbench,, dan DynamoDB untuk PartiQL. AWS Command Line Interface APIs 

Operasi PartiQL memberikan ketersediaan, latensi, dan performa yang sama seperti operasi bidang data DynamoDB lainnya.

Bagian berikut menjelaskan implementasi DynamoDB PartiQL.

**Topics**
+ [Apa yang dimaksud dengan PartiQL?](#ql-reference.what-is)
+ [PartiQL di Amazon DynamoDB](#ql-reference.what-is)
+ [Memulai](ql-gettingstarted.md)
+ [Jenis data](ql-reference.data-types.md)
+ [Pernyataan](ql-reference.statements.md)
+ [Fungsi](ql-functions.md)
+ [Operator](ql-operators.md)
+ [Transaksi](ql-reference.multiplestatements.transactions.md)
+ [Operasi batch](ql-reference.multiplestatements.batching.md)
+ [Kebijakan IAM](ql-iam.md)

## Apa yang dimaksud dengan PartiQL?
<a name="ql-reference.what-is"></a>

*PartiQL* menyediakan akses kueri yang kompatibel dengan SQL di beberapa penyimpanan data yang berisi data terstruktur, data semi terstruktur, dan data bersarang. Ini banyak digunakan di Amazon dan sekarang tersedia sebagai bagian dari banyak AWS layanan, termasuk DynamoDB.

Untuk spesifikasi PartiQL dan tutorial tentang bahasa kueri inti, lihat [Dokumentasi PartiQL](https://partiql.org/docs.html).

**catatan**  
Amazon DynamoDB mendukung *subset* dari bahasa kueri [PartiQL](https://partiql.org/).
Amazon DynamoDB tidak mendukung format data [Amazon ion](http://amzn.github.io/ion-docs/) atau literal Amazon Ion.

## PartiQL di Amazon DynamoDB
<a name="ql-reference.what-is"></a>

Untuk menjalankan kueri PartiQL di DynamoDB, Anda dapat menggunakan:
+ Konsol DynamoDB
+ NoSQL Workbench
+  AWS Command Line Interface (AWS CLI)
+ DynamoDB APIs

Untuk informasi tentang cara menggunakan metode ini guna mengakses DynamoDB, lihat [Mengakses DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AccessingDynamoDB.html).

# Mulai menggunakan PartiQL untuk DynamoDB
<a name="ql-gettingstarted"></a>

Bagian ini menjelaskan cara menggunakan PartiQL untuk DynamoDB dari konsol Amazon DynamoDB, (), dan DynamoDB. AWS Command Line Interface AWS CLI APIs

Dalam contoh berikut, tabel DynamoDB yang ditentukan dalam tutorial [Mulai menggunakan DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStartedDynamoDB.html) adalah prasyarat.

[Untuk informasi tentang menggunakan konsol DynamoDB, AWS Command Line Interface, atau DynamoDB untuk mengakses DynamoDB, lihat Mengakses APIs DynamoDB.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AccessingDynamoDB.html)

Untuk [mengunduh](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html) dan menggunakan [NoSQL workbench](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.html) untuk membuat pernyataan [PartiQL untuk DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html), pilih **operasi PartiQL** di sudut kanan atas [pembangun Operasi](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.querybuilder.operationbuilder.html) NoSQL Workbench untuk DynamoDB.

------
#### [ Console ]

![\[Antarmuka editor PartiQL yang menunjukkan hasil menjalankan operasi Query pada tabel Musik.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/partiqlgettingstarted.png)


1. Masuk ke Konsol Manajemen AWS dan buka konsol DynamoDB di. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Di panel navigasi di sisi kiri konsol, pilih **editor PartiQL**.

1. Pilih tabel **Musik**.

1. Pilih **tabel Kueri**. Tindakan ini menghasilkan kueri yang tidak akan menghasilkan pemindaian tabel penuh.

1. Ganti `partitionKeyValue` dengan nilai string `Acme Band`. Ganti `sortKeyValue` dengan nilai string `Happy Day`.

1. Pilih tombol **Jalankan**. 

1. Anda dapat melihat hasil kueri dengan memilih tombol **Tampilan tabel** atau **Tampilan JSON**. 

------
#### [ NoSQL workbench ]

![\[Antarmuka meja kerja NoSQL. Ini menunjukkan pernyataan PartiQL SELECT yang dapat Anda jalankan di tabel Musik.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/workbench/partiql.single.png)


1. Pilih **pernyataan PartiQL**.

1. Masukkan [pernyataan SELECT](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html) PartiQL berikut 

   ```
   SELECT *                                         
   FROM Music  
   WHERE Artist=? and SongTitle=?
   ```

1. Untuk menentukan nilai parameter `Artist` dan `SongTitle`:

   1. Pilih **Parameter permintaan opsional**.

   1. Pilih **Tambahkan parameter baru**.

   1. Pilih jenis atribut **string** dan nilai `Acme Band`.

   1. Ulangi langkah b dan c, lalu pilih jenis **string** dan nilai `PartiQL Rocks`. 

1. Jika Anda ingin membuat kode, pilih **Buat kode**.

   Pilih bahasa yang Anda inginkan dari tab yang ditampilkan. Sekarang Anda dapat menyalin kode ini dan menggunakannya dalam aplikasi Anda.

1. Jika Anda ingin operasi segera dijalankan, pilih **Jalankan**.

------
#### [ AWS CLI ]

1. Buat item dalam tabel `Music` menggunakan pernyataan PartiQL INSERT. 

   ```
   aws dynamodb execute-statement --statement "INSERT INTO Music  \
   					    VALUE  \
   					    {'Artist':'Acme Band','SongTitle':'PartiQL Rocks'}"
   ```

1. Ambil item dari tabel Musik menggunakan pernyataan PartiQL SELECT.

   ```
   aws dynamodb execute-statement --statement "SELECT * FROM Music   \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

1. Perbarui item dalam tabel `Music` menggunakan pernyataan PartiQL UPDATE.

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardsWon=1  \
                                               SET AwardDetail={'Grammys':[2020, 2018]}  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Tambahkan nilai daftar untuk item dalam tabel `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Hapus nilai daftar untuk item dalam tabel `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               REMOVE AwardDetail.Grammys[2]  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Tambahkan anggota peta baru untuk item dalam tabel `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardDetail.BillBoard=[2020]  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Tambahkan atribut set string baru untuk item dalam tabel `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET BandMembers =<<'member1', 'member2'>>  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Perbarui atribut set string untuk item dalam tabel `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET BandMembers =set_add(BandMembers, <<'newmember'>>)  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

1. Hapus item dari tabel `Music` menggunakan pernyataan PartiQL DELETE.

   ```
   aws dynamodb execute-statement --statement "DELETE  FROM Music  \
       WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

------
#### [ Java ]

```
import java.util.ArrayList;
import java.util.List;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import software.amazon.dynamodb.AmazonDynamoDB;
import software.amazon.dynamodb.AmazonDynamoDBClientBuilder;
import software.amazon.dynamodb.model.AttributeValue;
import software.amazon.dynamodb.model.ConditionalCheckFailedException;
import software.amazon.dynamodb.model.ExecuteStatementRequest;
import software.amazon.dynamodb.model.ExecuteStatementResult;
import software.amazon.dynamodb.model.InternalServerErrorException;
import software.amazon.dynamodb.model.ItemCollectionSizeLimitExceededException;
import software.amazon.dynamodb.model.ProvisionedThroughputExceededException;
import software.amazon.dynamodb.model.RequestLimitExceededException;
import software.amazon.dynamodb.model.ResourceNotFoundException;
import software.amazon.dynamodb.model.TransactionConflictException;

public class DynamoDBPartiQGettingStarted {

    public static void main(String[] args) {
        // Create the DynamoDB Client with the region you want
        AmazonDynamoDB dynamoDB = createDynamoDbClient("us-west-1");

        try {
            // Create ExecuteStatementRequest
            ExecuteStatementRequest executeStatementRequest = new ExecuteStatementRequest();
            List<AttributeValue> parameters= getPartiQLParameters();

            //Create an item in the Music table using the INSERT PartiQL statement
            processResults(executeStatementRequest(dynamoDB, "INSERT INTO Music value {'Artist':?,'SongTitle':?}", parameters));

            //Retrieve an item from the Music table using the SELECT PartiQL statement.
            processResults(executeStatementRequest(dynamoDB, "SELECT * FROM Music  where Artist=? and SongTitle=?", parameters));

            //Update an item in the Music table using the UPDATE PartiQL statement.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET AwardsWon=1 SET AwardDetail={'Grammys':[2020, 2018]}  where Artist=? and SongTitle=?", parameters));

            //Add a list value for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  where Artist=? and SongTitle=?", parameters));

            //Remove a list value for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music REMOVE AwardDetail.Grammys[2]   where Artist=? and SongTitle=?", parameters));

            //Add a new map member for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music set AwardDetail.BillBoard=[2020] where Artist=? and SongTitle=?", parameters));

            //Add a new string set attribute for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET BandMembers =<<'member1', 'member2'>> where Artist=? and SongTitle=?", parameters));

            //update a string set attribute for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET BandMembers =set_add(BandMembers, <<'newmember'>>) where Artist=? and SongTitle=?", parameters));

            //Retrieve an item from the Music table using the SELECT PartiQL statement.
            processResults(executeStatementRequest(dynamoDB, "SELECT * FROM Music  where Artist=? and SongTitle=?", parameters));

            //delete an item from the Music Table
            processResults(executeStatementRequest(dynamoDB, "DELETE  FROM Music  where Artist=? and SongTitle=?", parameters));
        } catch (Exception e) {
            handleExecuteStatementErrors(e);
        }
    }

    private static AmazonDynamoDB createDynamoDbClient(String region) {
        return AmazonDynamoDBClientBuilder.standard().withRegion(region).build();
    }

    private static List<AttributeValue> getPartiQLParameters() {
        List<AttributeValue> parameters = new ArrayList<AttributeValue>();
        parameters.add(new AttributeValue("Acme Band"));
        parameters.add(new AttributeValue("PartiQL Rocks"));
        return parameters;
    }

    private static ExecuteStatementResult executeStatementRequest(AmazonDynamoDB client, String statement, List<AttributeValue> parameters ) {
        ExecuteStatementRequest request = new ExecuteStatementRequest();
        request.setStatement(statement);
        request.setParameters(parameters);
        return client.executeStatement(request);
    }

    private static void processResults(ExecuteStatementResult executeStatementResult) {
        System.out.println("ExecuteStatement successful: "+ executeStatementResult.toString());

    }

    // Handles errors during ExecuteStatement execution. Use recommendations in error messages below to add error handling specific to
    // your application use-case.
    private static void handleExecuteStatementErrors(Exception exception) {
        try {
            throw exception;
        } catch (ConditionalCheckFailedException ccfe) {
            System.out.println("Condition check specified in the operation failed, review and update the condition " +
                                       "check before retrying. Error: " + ccfe.getErrorMessage());
        } catch (TransactionConflictException tce) {
            System.out.println("Operation was rejected because there is an ongoing transaction for the item, generally " +
                                       "safe to retry with exponential back-off. Error: " + tce.getErrorMessage());
        } catch (ItemCollectionSizeLimitExceededException icslee) {
            System.out.println("An item collection is too large, you\'re using Local Secondary Index and exceeded " +
                                       "size limit of items per partition key. Consider using Global Secondary Index instead. Error: " + icslee.getErrorMessage());
        } catch (Exception e) {
            handleCommonErrors(e);
        }
    }

    private static void handleCommonErrors(Exception exception) {
        try {
            throw exception;
        } catch (InternalServerErrorException isee) {
            System.out.println("Internal Server Error, generally safe to retry with exponential back-off. Error: " + isee.getErrorMessage());
        } catch (RequestLimitExceededException rlee) {
            System.out.println("Throughput exceeds the current throughput limit for your account, increase account level throughput before " +
                                       "retrying. Error: " + rlee.getErrorMessage());
        } catch (ProvisionedThroughputExceededException ptee) {
            System.out.println("Request rate is too high. If you're using a custom retry strategy make sure to retry with exponential back-off. " +
                                       "Otherwise consider reducing frequency of requests or increasing provisioned capacity for your table or secondary index. Error: " +
                                       ptee.getErrorMessage());
        } catch (ResourceNotFoundException rnfe) {
            System.out.println("One of the tables was not found, verify table exists before retrying. Error: " + rnfe.getErrorMessage());
        } catch (AmazonServiceException ase) {
            System.out.println("An AmazonServiceException occurred, indicates that the request was correctly transmitted to the DynamoDB " +
                                       "service, but for some reason, the service was not able to process it, and returned an error response instead. Investigate and " +
                                       "configure retry strategy. Error type: " + ase.getErrorType() + ". Error message: " + ase.getErrorMessage());
        } catch (AmazonClientException ace) {
            System.out.println("An AmazonClientException occurred, indicates that the client was unable to get a response from DynamoDB " +
                                       "service, or the client was unable to parse the response from the service. Investigate and configure retry strategy. "+
                                       "Error: " + ace.getMessage());
        } catch (Exception e) {
            System.out.println("An exception occurred, investigate and configure retry strategy. Error: " + e.getMessage());
        }
    }

}
```

------

## Menggunakan pernyataan berparameter
<a name="ql-gettingstarted.parameterized"></a>

Alih-alih menyematkan nilai secara langsung dalam string pernyataan PartiQL, Anda dapat menggunakan placeholder tanda tanya `?` () dan memberikan nilai secara terpisah di bidang. `Parameters` Masing-masing `?` diganti dengan nilai parameter yang sesuai, sesuai urutan yang disediakan.

Menggunakan pernyataan berparameter adalah praktik terbaik karena memisahkan struktur pernyataan dari nilai data, membuat pernyataan lebih mudah dibaca dan digunakan kembali. Ini juga menghindari kebutuhan untuk secara manual memformat dan melarikan diri nilai atribut dalam string pernyataan.

Pernyataan parameter didukung dalam`ExecuteStatement`,`BatchExecuteStatement`, dan `ExecuteTransaction` operasi.

Contoh berikut mengambil item dari `Music` tabel menggunakan nilai parameter untuk kunci partisi dan kunci sortir.

------
#### [ AWS CLI parameterized ]

```
aws dynamodb execute-statement \
    --statement "SELECT * FROM \"Music\" WHERE Artist=? AND SongTitle=?" \
    --parameters '[{"S": "Acme Band"}, {"S": "PartiQL Rocks"}]'
```

------
#### [ Java parameterized ]

```
List<AttributeValue> parameters = new ArrayList<>();
parameters.add(new AttributeValue("Acme Band"));
parameters.add(new AttributeValue("PartiQL Rocks"));

ExecuteStatementRequest request = new ExecuteStatementRequest()
    .withStatement("SELECT * FROM Music WHERE Artist=? AND SongTitle=?")
    .withParameters(parameters);

ExecuteStatementResult result = dynamoDB.executeStatement(request);
```

------
#### [ Python parameterized ]

```
response = dynamodb_client.execute_statement(
    Statement="SELECT * FROM Music WHERE Artist=? AND SongTitle=?",
    Parameters=[
        {'S': 'Acme Band'},
        {'S': 'PartiQL Rocks'}
    ]
)
```

------

**catatan**  
Contoh Java di bagian memulai sebelumnya menggunakan pernyataan berparameter di seluruh. `getPartiQLParameters()`Metode ini membangun daftar parameter, dan setiap pernyataan menggunakan `?` placeholder alih-alih nilai inline.

# Jenis data PartiQL untuk DynamoDB
<a name="ql-reference.data-types"></a>

Tabel berikut mencantumkan jenis data yang dapat Anda gunakan dengan PartiQL untuk DynamoDB.

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/ql-reference.data-types.html)

## Contoh
<a name="ql-reference.data-types"></a>

Pernyataan berikut menunjukkan cara memasukkan jenis data berikut: `String`, `Number`, `Map`, `List`, `Number Set`, dan `String Set`.

```
INSERT INTO TypesTable value {'primarykey':'1', 
'NumberType':1,
'MapType' : {'entryname1': 'value', 'entryname2': 4}, 
'ListType': [1,'stringval'], 
'NumberSetType':<<1,34,32,4.5>>, 
'StringSetType':<<'stringval','stringval2'>>
}
```

Pernyataan berikut menunjukkan cara menyisipkan elemen baru ke dalam jenis `Map`, `List`, `Number Set`, and `String Set` serta mengubah nilai jenis `Number`.

```
UPDATE TypesTable 
SET NumberType=NumberType + 100 
SET MapType.NewMapEntry=[2020, 'stringvalue', 2.4]
SET ListType = LIST_APPEND(ListType, [4, <<'string1', 'string2'>>])
SET NumberSetType= SET_ADD(NumberSetType, <<345, 48.4>>)
SET StringSetType = SET_ADD(StringSetType, <<'stringsetvalue1', 'stringsetvalue2'>>)
WHERE primarykey='1'
```

Pernyataan berikut menunjukkan cara menghapus elemen dari jenis `Map`, `List`, `Number Set`, and `String Set` serta mengubah nilai jenis `Number`.

```
UPDATE TypesTable 
SET NumberType=NumberType - 1
REMOVE ListType[1]
REMOVE MapType.NewMapEntry
SET NumberSetType = SET_DELETE( NumberSetType, <<345>>)
SET StringSetType = SET_DELETE( StringSetType, <<'stringsetvalue1'>>)
WHERE primarykey='1'
```

Untuk informasi selengkapnya, lihat [jenis data DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes).

# Pernyataan PartiQL untuk DynamoDB
<a name="ql-reference.statements"></a>

Amazon DynamoDB mendukung pernyataan PartiQL berikut.

**catatan**  
DynamoDB tidak mendukung semua pernyataan PartiQL.  
Referensi ini memberikan sintaks dasar dan contoh penggunaan pernyataan PartiQL yang Anda jalankan secara manual menggunakan or. AWS CLI APIs

*Bahasa manipulasi data* (DML) adalah kumpulan pernyataan PartiQL yang Anda gunakan untuk mengelola data dalam tabel DynamoDB. Anda menggunakan pernyataan DML untuk menambah, mengubah, atau menghapus data dalam sebuah tabel.

Berikut DML dan kueri bahasa pernyataan yang didukung:
+ [Pernyataan pemilihan PartiQL untuk DynamoDB](ql-reference.select.md)
+ [Pernyataan pembaruan PartiQL untuk DynamoDB](ql-reference.update.md)
+ [Pernyataan sisipkan PartiQL untuk DynamoDB](ql-reference.insert.md)
+ [Pernyataan hapus PartiQL untuk DynamoDB](ql-reference.delete.md)

[Melakukan transaksi dengan PartiQL untuk DynamoDB](ql-reference.multiplestatements.transactions.md) and [Menjalankan operasi batch dengan PartiQL untuk DynamoDB](ql-reference.multiplestatements.batching.md) juga didukung oleh PartiQL untuk DynamoDB.

# Pernyataan pemilihan PartiQL untuk DynamoDB
<a name="ql-reference.select"></a>

Gunakan pernyataan `SELECT` untuk mengambil data dari tabel di Amazon DynamoDB.

Menggunakan `SELECT` pernyataan dapat menghasilkan pemindaian tabel lengkap jika kondisi kesetaraan atau IN dengan kunci partisi tidak disediakan dalam klausa WHERE. Operasi pemindaian memeriksa setiap item untuk nilai yang diminta dan dapat menggunakan throughput yang disediakan untuk indeks atau tabel besar dalam satu operasi. 

Jika ingin menghindari pemindaian tabel secara lengkap di PartiQL, Anda dapat:
+ Menulis pernyataan `SELECT` Anda agar tidak memindai tabel secara lengkap dengan memastikan [ketentuan klausul WHERE](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html#ql-reference.select.parameters) Anda dikonfigurasi dengan semestinya.
+ Menonaktifkan pemindaian tabel lengkap menggunakan kebijakan IAM yang ditentukan di [Contoh: Mengizinkan pernyataan pilihan dan menolak pernyataan pemindaian tabel lengkap di PartiQL untuk DynamoDB](ql-iam.md#access-policy-ql-iam-example6), dalam panduan developer DynamoDB.

Untuk informasi selengkapnya, lihat [Praktik terbaik untuk Mengkueri dan memindai data](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-query-scan.html), dalam panduan developer DynamoDB.

**Topics**
+ [Sintaks](#ql-reference.select.syntax)
+ [Parameter](#ql-reference.select.parameters)
+ [Contoh](#ql-reference.select.examples)

## Sintaks
<a name="ql-reference.select.syntax"></a>

```
SELECT expression  [, ...] 
FROM table[.index]
[ WHERE condition ] [ [ORDER BY key [DESC|ASC] , ...]
```

## Parameter
<a name="ql-reference.select.parameters"></a>

***expression***  
(Diperlukan) Proyeksi yang terbentuk dari wildcard `*` atau daftar proyeksi dari satu nama atribut atau lebih atau jalur dokumen dari set hasil. Ekspresi dapat terdiri dari panggilan ke [Gunakan fungsi PartiQL dengan DynamoDB](ql-functions.md) atau bidang yang diubah oleh [Aritmatika PartiQL, perbandingan, dan operator logika untuk DynamoDB](ql-operators.md).

***table***  
(Diperlukan) Nama tabel untuk kueri.

***index***  
(Opsional) Nama indeks untuk kueri.  
Anda harus menambahkan tanda kutip ganda ke nama tabel dan nama indeks saat mengkueri indeks.  

```
SELECT * 
FROM "TableName"."IndexName"
```

***condition***  
(Opsional) Kriteria seleksi untuk kueri.  
Untuk memastikan bahwa pernyataan `SELECT` tidak menghasilkan pemindaian tabel secara lengkap, kondisi klausul `WHERE` harus menentukan kunci partisi. Gunakan kesetaraan atau operator IN.  
Misalnya, jika Anda memiliki tabel `Orders` dengan kunci partisi `OrderID` dan atribut non-kunci lainnya, termasuk `Address`, pernyataan berikut tidak akan menghasilkan pemindaian tabel secara lengkap:  

```
SELECT * 
FROM "Orders" 
WHERE OrderID = 100

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 and Address='some address'

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 or OrderID = 200

SELECT * 
FROM "Orders" 
WHERE OrderID IN [100, 300, 234]
```
Namun, pernyataan `SELECT` berikut akan menghasilkan pemindaian tabel secara lengkap:  

```
SELECT * 
FROM "Orders" 
WHERE OrderID > 1

SELECT * 
FROM "Orders" 
WHERE Address='some address'

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 OR Address='some address'
```

***key***  
(Opsional) Kunci hash atau kunci urutan untuk digunakan dalam mengurutkan hasil yang dikembalikan. Urutan defaultnya adalah naik (`ASC`) tentukan `DESC` jika Anda ingin hasil dikembalikan dalam urutan turun.

**catatan**  
Jika Anda menghapus klausul `WHERE`, semua item dalam tabel akan diambil.

## Contoh
<a name="ql-reference.select.examples"></a>

Kueri berikut mengembalikan satu item, jika ada, dari tabel `Orders` dengan menentukan kunci partisi, `OrderID`, dan menggunakan operator kesetaraan.

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID = 1
```

Kueri berikut mengembalikan semua item dalam tabel `Orders` yang memiliki kunci partisi spesifik, `OrderID`, nilai menggunakan operator OR.

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID = 1 OR OrderID = 2
```

Kueri berikut mengembalikan semua item dalam tabel `Orders` yang memiliki kunci partisi spesifik, `OrderID`, nilai menggunakan operator IN. Hasil yang dikembalikan dalam urutan turun, berdasarkan nilai atribut kunci `OrderID`.

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID IN [1, 2, 3] ORDER BY OrderID DESC
```

Kueri berikut menunjukkan pemindaian tabel secara lengkap yang mengembalikan semua item dari tabel `Orders` yang memiliki `Total` lebih dari 500, dengan `Total` adalah atribut non-kunci.

```
SELECT OrderID, Total 
FROM "Orders"
WHERE Total > 500
```

Kueri berikut menunjukkan pemindaian tabel secara lengkap yang mengembalikan semua item dari tabel `Orders` di dalam rentang urutan `Total` tertentu, menggunakan operator IN dan atribut non-kunci `Total`.

```
SELECT OrderID, Total 
FROM "Orders"
WHERE Total IN [500, 600]
```

Kueri berikut menunjukkan pemindaian tabel secara lengkap yang mengembalikan semua item dari tabel `Orders` di dalam rentang urutan `Total` tertentu, menggunakan operator BETWEEN dan atribut non-kunci `Total`.

```
SELECT OrderID, Total 
FROM "Orders" 
WHERE Total BETWEEN 500 AND 600
```

Kueri berikut mengembalikan tanggal pertama perangkat firestick digunakan untuk menonton dengan menentukan kunci partisi `CustomerID` dan kunci urutan `MovieID` dalam kondisi klausul WHERE dan menggunakan jalur dokumen dalam klausul SELECT.

```
SELECT Devices.FireStick.DateWatched[0] 
FROM WatchList 
WHERE CustomerID= 'C1' AND MovieID= 'M1'
```

Kueri berikut menunjukkan pemindaian tabel secara penuh yang mengembalikan daftar item tempat perangkat firestick pertama kali digunakan setelah 24/12/19 menggunakan jalur dokumen dalam kondisi klausul WHERE.

```
SELECT Devices 
FROM WatchList 
WHERE Devices.FireStick.DateWatched[0] >= '12/24/19'
```

# Pernyataan pembaruan PartiQL untuk DynamoDB
<a name="ql-reference.update"></a>

Gunakan pernyataan `UPDATE` untuk mengubah nilai dari satu atribut atau lebih dalam item dalam tabel Amazon DynamoDB. 

**catatan**  
Anda hanya dapat memperbarui satu item pada satu waktu; Anda tidak dapat mengeluarkan pernyataan DynamoDB PartiQL tunggal yang memperbarui beberapa item. Untuk informasi tentang memperbarui beberapa item, lihat [Melakukan transaksi dengan PartiQL untuk DynamoDB](ql-reference.multiplestatements.transactions.md) atau [Menjalankan operasi batch dengan PartiQL untuk DynamoDB](ql-reference.multiplestatements.batching.md).

**Topics**
+ [Sintaks](#ql-reference.update.syntax)
+ [Parameter](#ql-reference.update.parameters)
+ [Nilai yang dikembalikan](#ql-reference.update.return)
+ [Contoh](#ql-reference.update.examples)

## Sintaks
<a name="ql-reference.update.syntax"></a>

```
UPDATE  table  
[SET | REMOVE]  path  [=  data] […]
WHERE condition [RETURNING returnvalues]
<returnvalues>  ::= [ALL OLD | MODIFIED OLD | ALL NEW | MODIFIED NEW] *
```

## Parameter
<a name="ql-reference.update.parameters"></a>

***table***  
(Diperlukan) Tabel yang berisi data yang akan diubah.

***path***  
(Diperlukan) Nama atribut atau jalur dokumen yang akan dibuat atau diubah.

***data***  
(Diperlukan) Nilai atribut atau hasil operasi.  
Operasi yang didukung untuk digunakan bersama SET:  
+ LIST\$1APPEND: menambahkan nilai ke jenis daftar.
+ SET\$1ADD: menambahkan nilai ke set angka atau string.
+ SET\$1DELETE: menghapus nilai dari set angka atau string.

***condition***  
(Diperlukan) Kriteria pemilihan untuk item yang akan diubah. Syarat ini harus diselesaikan untuk satu nilai kunci primer.

***returnvalues***  
(Opsional) Gunakan `returnvalues` jika Anda ingin mendapatkan atribut item seperti yang muncul sebelum atau setelah diperbarui. Nilai yang valid adalah:   
+ `ALL OLD *`- Mengembalikan semua atribut item, saat atribut item tersebut muncul sebelum operasi pembaruan.
+ `MODIFIED OLD *`- Mengembalikan hanya atribut yang diperbarui, saat atribut item tersebut muncul sebelum operasi pembaruan.
+ `ALL NEW *`- Mengembalikan semua atribut item, seperti yang muncul setelah operasi pembaruan.
+ `MODIFIED NEW *`- Hanya mengembalikan atribut yang diperbarui, seperti yang muncul setelah operasi `UpdateItem`.

## Nilai yang dikembalikan
<a name="ql-reference.update.return"></a>

Pernyataan ini tidak mengembalikan nilai kecuali parameter `returnvalues` ditentukan.

**catatan**  
Jika klausul WHERE pernyataan UPDATE tidak dinilai true untuk item apa pun dalam tabel DynamoDB, `ConditionalCheckFailedException` akan dikembalikan.

## Contoh
<a name="ql-reference.update.examples"></a>

Memperbarui nilai atribut dalam item yang sudah ada. Jika atribut tersebut tidak ada, atribut tersebut akan dibuat.

Kueri berikut memperbarui item dalam tabel `"Music"` dengan menambahkan atribut dari nomor jenis (`AwardsWon`) dan atribut dari jenis peta (`AwardDetail`).

```
UPDATE "Music" 
SET AwardsWon=1 
SET AwardDetail={'Grammys':[2020, 2018]}  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

Anda dapat menambahkan `RETURNING ALL OLD *` untuk mengembalikan atribut seperti yang muncul sebelum operasi `Update`.

```
UPDATE "Music" 
SET AwardsWon=1 
SET AwardDetail={'Grammys':[2020, 2018]}  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
RETURNING ALL OLD *
```

Ini akan menghasilkan hal berikut:

```
{
    "Items": [
        {
            "Artist": {
                "S": "Acme Band"
            },
            "SongTitle": {
                "S": "PartiQL Rocks"
            }
        }
    ]
}
```

Anda dapat menambahkan `RETURNING ALL NEW *` untuk mengembalikan atribut seperti yang muncul setelah operasi `Update`.

```
UPDATE "Music" 
SET AwardsWon=1 
SET AwardDetail={'Grammys':[2020, 2018]}  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
RETURNING ALL NEW *
```

Ini akan menghasilkan hal berikut:

```
{
    "Items": [
        {
            "AwardDetail": {
                "M": {
                    "Grammys": {
                        "L": [
                            {
                                "N": "2020"
                            },
                            {
                                "N": "2018"
                            }
                        ]
                    }
                }
            },
            "AwardsWon": {
                "N": "1"
            }
        }
    ]
}
```

Kueri berikut memperbarui item dalam tabel `"Music"` dengan menambahkan ke daftar `AwardDetail.Grammys`.

```
UPDATE "Music" 
SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

Kueri berikut memperbarui item dalam tabel `"Music"` dengan menghapus dari daftar `AwardDetail.Grammys`.

```
UPDATE "Music" 
REMOVE AwardDetail.Grammys[2]   
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

Kueri berikut memperbarui item dalam tabel `"Music"` dengan menambahkan `BillBoard` ke peta `AwardDetail`.

```
UPDATE "Music" 
SET AwardDetail.BillBoard=[2020] 
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

Kueri berikut memperbarui item dalam tabel `"Music"` dengan menambahkan atribut set string `BandMembers`.

```
UPDATE "Music" 
SET BandMembers =<<'member1', 'member2'>> 
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

Kueri berikut memperbarui item dalam tabel `"Music"` dengan menambahkan `newbandmember` ke set string `BandMembers`.

```
UPDATE "Music" 
SET BandMembers =set_add(BandMembers, <<'newbandmember'>>) 
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

# Pernyataan hapus PartiQL untuk DynamoDB
<a name="ql-reference.delete"></a>

Gunakan pernyataan `DELETE` untuk menghapus item yang sudah ada dari tabel Amazon DynamoDB Anda.

**catatan**  
Anda hanya dapat menghapus satu item dalam satu waktu. Anda tidak dapat mengeluarkan pernyataan DynamoDB PartiQL tunggal yang menghapus beberapa item. Untuk informasi tentang menghapus beberapa item, lihat [Melakukan transaksi dengan PartiQL untuk DynamoDB](ql-reference.multiplestatements.transactions.md) atau [Menjalankan operasi batch dengan PartiQL untuk DynamoDB](ql-reference.multiplestatements.batching.md).

**Topics**
+ [Sintaks](#ql-reference.delete.syntax)
+ [Parameter](#ql-reference.delete.parameters)
+ [Nilai yang dikembalikan](#ql-reference.delete.return)
+ [Contoh](#ql-reference.delete.examples)

## Sintaks
<a name="ql-reference.delete.syntax"></a>

```
DELETE FROM table 
 WHERE condition [RETURNING returnvalues]
 <returnvalues>  ::= ALL OLD *
```

## Parameter
<a name="ql-reference.delete.parameters"></a>

***table***  
(Diperlukan) Tabel DynamoDB yang berisi item yang akan dihapus.

***condition***  
(Diperlukan) Kriteria seleksi untuk item yang akan dihapus; syarat ini harus diselesaikan untuk nilai kunci primer tunggal.

***returnvalues***  
(Opsional) Gunakan `returnvalues` jika Anda ingin mendapatkan atribut item seperti yang muncul sebelum atribut item tersebut dihapus. Nilai yang valid adalah:   
+ `ALL OLD *`- Konten dari item lama akan dikembalikan.

## Nilai yang dikembalikan
<a name="ql-reference.delete.return"></a>

Pernyataan ini tidak mengembalikan nilai kecuali parameter `returnvalues` ditentukan.

**catatan**  
Jika tabel DynamoDB tidak memiliki item dengan kunci primer yang sama seperti yang item yang DELETE-nya dikeluarkan, SUCCESS dikembalikan dengan 0 item dihapus. Jika tabel memiliki item dengan kunci primer yang sama, tetapi syarat dalam klausul WHERE pernyataan dari DELETE bernilai false, `ConditionalCheckFailedException` akan dikembalikan.

## Contoh
<a name="ql-reference.delete.examples"></a>

Kueri berikut akan menghapus item dalam tabel `"Music"`.

```
DELETE FROM "Music" WHERE "Artist" = 'Acme Band' AND "SongTitle" = 'PartiQL Rocks'
```

Anda dapat menambahkan parameter `RETURNING ALL OLD *` untuk mengembalikan data yang telah dihapus.

```
DELETE FROM "Music" WHERE "Artist" = 'Acme Band' AND "SongTitle" = 'PartiQL Rocks' RETURNING ALL OLD *
```

Pernyataan `Delete` sekarang mengembalikan yang berikut:

```
{
    "Items": [
        {
            "Artist": {
                "S": "Acme Band"
            },
            "SongTitle": {
                "S": "PartiQL Rocks"
            }
        }
    ]
}
```

# Pernyataan sisipkan PartiQL untuk DynamoDB
<a name="ql-reference.insert"></a>

Gunakan pernyataan `INSERT` untuk menambahkan item ke tabel di Amazon DynamoDB.

**catatan**  
Anda hanya dapat menyisipkan satu item pada satu waktu; Anda tidak dapat mengeluarkan pernyataan DynamoDB PartiQL tunggal yang menyisipkan beberapa item. Untuk informasi tentang cara menyisipkan beberapa item, lihat [Melakukan transaksi dengan PartiQL untuk DynamoDB](ql-reference.multiplestatements.transactions.md) atau [Menjalankan operasi batch dengan PartiQL untuk DynamoDB](ql-reference.multiplestatements.batching.md).

**Topics**
+ [Sintaksis](#ql-reference.insert.syntax)
+ [Parameter](#ql-reference.insert.parameters)
+ [Nilai yang dikembalikan](#ql-reference.insert.return)
+ [Contoh](#ql-reference.insert.examples)

## Sintaksis
<a name="ql-reference.insert.syntax"></a>

Sisipkan satu item.

```
INSERT INTO table VALUE item
```

## Parameter
<a name="ql-reference.insert.parameters"></a>

***table***  
(Diperlukan) Tabel tempat Anda ingin menyisipkan data. Tabel harus sudah ada.

***item***  
(Diperlukan) Item DynamoDB yang valid diwakili sebagai [tupel PartiQL](https://partiql.org/docs.html). Anda harus menentukan hanya *satu* item dan setiap nama atribut dalam item adalah peka huruf besar-kecil dan dapat dilambangkan dengan tanda petik *tunggal* (`'...'`) di PartiQL.  
Nilai string juga dilambangkan dengan tanda petik *tunggal* (`'...'`) di PartiQL.

## Nilai yang dikembalikan
<a name="ql-reference.insert.return"></a>

Pernyataan ini tidak mengembalikan nilai apa pun.

**catatan**  
Jika tabel DynamoDB sudah memiliki item dengan kunci primer yang sama sebagai kunci primer dari item yang sedang disisipkan, `DuplicateItemException` dikembalikan.

## Contoh
<a name="ql-reference.insert.examples"></a>

```
INSERT INTO "Music" value {'Artist' : 'Acme Band','SongTitle' : 'PartiQL Rocks'}
```

# Gunakan fungsi PartiQL dengan DynamoDB
<a name="ql-functions"></a>

PartiQL di Amazon DynamoDB mendukung varian bawaan fungsi standar SQL berikut.

**catatan**  
Fungsi SQL apa pun yang tidak termasuk dalam daftar ini saat ini tidak didukung di DynamoDB.

## Fungsi agregat
<a name="ql-functions.aggregate"></a>
+ [Menggunakan Fungsi SIZE dengan PartiQL untuk Amazon DynamoDB](ql-functions.size.md)

## Fungsi kondisional
<a name="ql-functions.conditional"></a>
+ [Menggunakan fungsi EXISTS dengan PartiQL untuk DynamoDB](ql-functions.exists.md)
+ [Menggunakan Fungsi ATTRIBUTE\$1TYPE dengan PartiQL untuk DynamoDB](ql-functions.attribute_type.md)
+ [Menggunakan Fungsi BEGINS\$1WITH dengan PartiQL untuk DynamoDB](ql-functions.beginswith.md)
+ [Menggunakan fungsi COUNTAINS dengan PartiQL untuk DynamoDB](ql-functions.contains.md)
+ [Menggunakan fungsi MISSING dengan PartiQL untuk DynamoDB](ql-functions.missing.md)

# Menggunakan fungsi EXISTS dengan PartiQL untuk DynamoDB
<a name="ql-functions.exists"></a>

Anda dapat menggunakan EXISTS untuk melakukan fungsi yang sama seperti `ConditionCheck` di [TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems)API. Fungsi EXISTS hanya dapat digunakan dalam transaksi.

Dengan nilai, mengembalikan `TRUE` jika nilai adalah kumpulan yang tidak kosong. Jika tidak, mengembalikan `FALSE`.

**catatan**  
Fungsi ini hanya dapat digunakan dalam operasi transaksional.

## Sintaks
<a name="ql-functions.exists.syntax"></a>

```
EXISTS ( statement )
```

## Pendapat
<a name="ql-functions.exists.arguments"></a>

*statement*  
(Diperlukan) Pernyataan SELECT yang dievaluasi oleh fungsi.  
Pernyataan SELECT harus menentukan kunci primer lengkap dan satu kondisi lainnya.

## Jenis pengembalian
<a name="ql-functions.exists.return-type"></a>

`bool`

## Contoh
<a name="ql-functions.exists.examples"></a>

```
EXISTS(
    SELECT * FROM "Music" 
    WHERE "Artist" = 'Acme Band' AND "SongTitle" = 'PartiQL Rocks')
```

# Menggunakan Fungsi BEGINS\$1WITH dengan PartiQL untuk DynamoDB
<a name="ql-functions.beginswith"></a>

Mengembalikan `TRUE` jika atribut yang ditentukan dimulai dengan substring tertentu.

## Sintaks
<a name="ql-functions.beginswith.syntax"></a>

```
begins_with(path, value )
```

## Pendapat
<a name="ql-functions.beginswith.arguments"></a>

*path*  
(Diperlukan) Nama atribut atau jalur dokumen yang akan digunakan.

*value*  
(Diperlukan) String untuk mencari.

## Jenis pengembalian
<a name="ql-functions.beginswith.return-type"></a>

`bool`

## Contoh
<a name="ql-functions.beginswith.examples"></a>

```
SELECT * FROM "Orders" WHERE "OrderID"=1 AND begins_with("Address", '7834 24th')
```

# Menggunakan fungsi MISSING dengan PartiQL untuk DynamoDB
<a name="ql-functions.missing"></a>

Mengembalikan `TRUE` jika item tidak berisi atribut yang ditentukan. Hanya operator kesetaraan dan ketidaksetaraan yang dapat digunakan dengan fungsi ini.

## Sintaks
<a name="ql-functions.missing.syntax"></a>

```
 attributename IS | IS NOT  MISSING 
```

## Pendapat
<a name="ql-functions.missing.arguments"></a>

*attributename*  
(Diperlukan) Nama atribut yang akan dicari.

## Jenis pengembalian
<a name="ql-functions.missing.return-type"></a>

`bool`

## Contoh
<a name="ql-functions.missing.examples"></a>

```
SELECT * FROM Music WHERE "Awards" is MISSING
```

# Menggunakan Fungsi ATTRIBUTE\$1TYPE dengan PartiQL untuk DynamoDB
<a name="ql-functions.attribute_type"></a>

Mengembalikan `TRUE` jika atribut pada jalur yang ditentukan adalah jenis data tertentu.

## Sintaks
<a name="ql-functions.attribute_type.syntax"></a>

```
attribute_type( attributename, type )
```

## Pendapat
<a name="ql-functions.attribute_type.arguments"></a>

*attributename*  
(Diperlukan) Nama atribut yang digunakan.

*type*  
(Wajib) Jenis atribut yang akan diperiksa. Untuk daftar nilai yang valid, lihat [attribute\$1type](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) DynamoDB.

## Jenis pengembalian
<a name="ql-functions.attribute_type.return-type"></a>

`bool`

## Contoh
<a name="ql-functions.attribute_type.examples"></a>

```
SELECT * FROM "Music" WHERE attribute_type("Artist", 'S')
```

# Menggunakan fungsi COUNTAINS dengan PartiQL untuk DynamoDB
<a name="ql-functions.contains"></a>

Mengembalikan `TRUE` jika atribut yang ditentukan oleh jalur tersebut adalah salah satu dari hal berikut:
+ String yang berisi substring tertentu. 
+ Set yang berisi elemen tertentu dalam set.

Untuk informasi selengkapnya, lihat fungsi [contains](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) DynamoDB. 

## Sintaks
<a name="ql-functions.contains.syntax"></a>

```
contains( path, substring )
```

## Pendapat
<a name="ql-functions.contains.arguments"></a>

*path*  
(Diperlukan) Nama atribut atau jalur dokumen yang akan digunakan.

*substring*  
(Diperlukan) Substring atribut atau anggota yang ditetapkan yang akan diperiksa. Untuk informasi selengkapnya, lihat fungsi [contains](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) DynamoDB.

## Jenis pengembalian
<a name="ql-functions.contains.return-type"></a>

`bool`

## Contoh
<a name="ql-functions.contains.examples"></a>

```
SELECT * FROM "Orders" WHERE "OrderID"=1 AND contains("Address", 'Kirkland')
```

# Menggunakan Fungsi SIZE dengan PartiQL untuk Amazon DynamoDB
<a name="ql-functions.size"></a>

Mengembalikan angka yang mewakili ukuran atribut dalam byte. Berikut ini adalah jenis daya yang valid untuk digunakan dengan size. Untuk informasi selengkapnya, lihat fungsi [size](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) DynamoDB.

## Sintaks
<a name="ql-functions.size.syntax"></a>

```
size( path)
```

## Pendapat
<a name="ql-functions.size.arguments"></a>

*path*  
(Diperlukan) Nama atribut atau jalur dokumen.   
Untuk jenis yang didukung, lihat fungsi [size](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) DynamoDB.

## Jenis pengembalian
<a name="ql-functions.size.return-type"></a>

`int`

## Contoh
<a name="ql-functions.size.examples"></a>

```
 SELECT * FROM "Orders" WHERE "OrderID"=1 AND size("Image") >300
```

# Aritmatika PartiQL, perbandingan, dan operator logika untuk DynamoDB
<a name="ql-operators"></a>

PartiQL di Amazon DynamoDB mendukung [Operator standar SQL](https://www.w3schools.com/sql/sql_operators.asp) berikut.

**catatan**  
Operator SQL apa pun yang tidak termasuk dalam daftar ini saat ini tidak didukung di DynamoDB.

## Operator aritmatika
<a name="ql-operators.arithmetic"></a>


****  

| Operator | Deskripsi | 
| --- | --- | 
| \$1 | Tambahkan | 
| - | Kurangi | 

## Operator perbandingan
<a name="ql-operators.comparison"></a>


****  

| Operator | Deskripsi | 
| --- | --- | 
| = | Sama dengan | 
| <> | Tidak Sama dengan | 
| \$1= | Tidak Sama dengan | 
| > | Lebih besar dari | 
| < | Kurang dari | 
| >= | Lebih besar dari atau sama dengan | 
| <= | Kurang dari atau sama dengan | 

## Operator logis
<a name="ql-operators.logical"></a>


****  

| Operator | Deskripsi | 
| --- | --- | 
| AND | TRUE jika semua kondisi yang dipisahkan oleh AND adalah TRUE | 
| BETWEEN |  `TRUE`jika operan berada dalam kisaran perbandingan. Operator ini termasuk batas bawah dan atas operan tempat Anda menerapkannya.  | 
| IN | `TRUE`jika operan sama dengan salah satu daftar ekspresi (maksimal 50 nilai atribut hash atau maksimal 100 nilai atribut non-kunci). Hasil dikembalikan dalam halaman hingga 10 item. Jika `IN` daftar berisi lebih banyak nilai, Anda harus menggunakan yang `NextToken` dikembalikan dalam respons untuk mengambil halaman berikutnya. | 
| IS | TRUE jika operannya adalah jenis data PartiQL tertentu, termasuk NULL atau MISSING | 
| NOT | Membalikkan nilai ekspresi Boolean yang diberikan | 
| OR | TRUE jika semua kondisi yang dipisahkan oleh OR adalah TRUE | 

Untuk informasi selengkapnya tentang menggunakan operator logika, lihat [Membuat perbandingan](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.Comparators) dan[Evaluasi logika](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.LogicalEvaluations).

# Melakukan transaksi dengan PartiQL untuk DynamoDB
<a name="ql-reference.multiplestatements.transactions"></a>

Bagian ini menjelaskan cara menggunakan transaksi dengan PartiQL untuk DynamoDB. Transaksi PartiQL dibatasi hingga 100 total pernyataan (tindakan).

Untuk informasi lebih lanjut tentang transaksi DynamoDB, lihat [Mengelola alur kerja kompleks dengan transaksi DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html).

**catatan**  
Seluruh transaksi harus terdiri dari pernyataan baca atau pernyataan tulis. Anda tidak dapat menggabungkan keduanya dalam satu transaksi. Fungsi EXISTS merupakan pengecualian. Anda dapat menggunakannya untuk memeriksa kondisi atribut tertentu dari item dengan cara yang mirip `ConditionCheck` dengan operasi [TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems)API.

**Topics**
+ [Sintaks](#ql-reference.multiplestatements.transactions.syntax)
+ [Parameter](#ql-reference.multiplestatements.transactions.parameters)
+ [Nilai yang dikembalikan](#ql-reference.multiplestatements.transactions.return)
+ [Contoh](#ql-reference.multiplestatements.transactions.examples)

## Sintaks
<a name="ql-reference.multiplestatements.transactions.syntax"></a>

```
[
   {
      "Statement":" statement ",
      "Parameters":[
         {
            " parametertype " : " parametervalue "
         }, ...]
   } , ...
]
```

## Parameter
<a name="ql-reference.multiplestatements.transactions.parameters"></a>

***statement***  
(Diperlukan) Pernyataan yang didukung PartiQL untuk DynamoDB.  
Seluruh transaksi harus terdiri dari pernyataan baca atau pernyataan tulis. Anda tidak dapat menggabungkan keduanya dalam satu transaksi.

***parametertype***  
(Opsional) Jenis DynamoDB, jika parameter digunakan saat menentukan pernyataan PartiQL.

***parametervalue***  
(Opsional) Nilai parameter jika parameter digunakan saat menentukan pernyataan PartiQL.

## Nilai yang dikembalikan
<a name="ql-reference.multiplestatements.transactions.return"></a>

Pernyataan ini tidak mengembalikan nilai apa pun untuk operasi Tulis (INSERT, UPDATE, atau DELETE). Namun, ia mengembalikan nilai yang berbeda untuk operasi Baca (SELECT) berdasarkan kondisi yang ditentukan dalam klausul WHERE.

**catatan**  
Jika salah satu operasi INSERT, UPDATE, atau DELETE singleton mengembalikan kesalahan, transaksi dibatalkan dengan pengecualian `TransactionCanceledException`, dan kode alasan pembatalan termasuk kesalahan dari operasi singleton individual.

## Contoh
<a name="ql-reference.multiplestatements.transactions.examples"></a>

Contoh berikut menjalankan beberapa pernyataan sebagai sebuah transaksi.

------
#### [ AWS CLI ]

1. Simpan kode JSON berikut ke file bernama partiql.json. 

   ```
   [
       {
           "Statement": "EXISTS(SELECT * FROM \"Music\" where Artist='No One You Know' and SongTitle='Call Me Today' and Awards is  MISSING)"
       },
       {
           "Statement": "INSERT INTO Music value {'Artist':?,'SongTitle':'?'}",
           "Parameters": [{\"S\": \"Acme Band\"}, {\"S\": \"Best Song\"}]
       },
       {
           "Statement": "UPDATE \"Music\" SET AwardsWon=1 SET AwardDetail={'Grammys':[2020, 2018]}  where Artist='Acme Band' and SongTitle='PartiQL Rocks'"
       }
   ]
   ```

1. Jalankan perintah berikut di prompt perintah.

   ```
   aws dynamodb execute-transaction --transact-statements  file://partiql.json
   ```

------
#### [ Java ]

```
public class DynamoDBPartiqlTransaction {

    public static void main(String[] args) {
        // Create the DynamoDB Client with the region you want
        AmazonDynamoDB dynamoDB = createDynamoDbClient("us-west-2");
        
        try {
            // Create ExecuteTransactionRequest
            ExecuteTransactionRequest executeTransactionRequest = createExecuteTransactionRequest();
            ExecuteTransactionResult executeTransactionResult = dynamoDB.executeTransaction(executeTransactionRequest);
            System.out.println("ExecuteTransaction successful.");
            // Handle executeTransactionResult

        } catch (Exception e) {
            handleExecuteTransactionErrors(e);
        }
    }

    private static AmazonDynamoDB createDynamoDbClient(String region) {
        return AmazonDynamoDBClientBuilder.standard().withRegion(region).build();
    }

    private static ExecuteTransactionRequest createExecuteTransactionRequest() {
        ExecuteTransactionRequest request = new ExecuteTransactionRequest();
        
        // Create statements
        List<ParameterizedStatement> statements = getPartiQLTransactionStatements();

        request.setTransactStatements(statements);
        return request;
    }

    private static List<ParameterizedStatement> getPartiQLTransactionStatements() {
        List<ParameterizedStatement> statements = new ArrayList<ParameterizedStatement>();

        statements.add(new ParameterizedStatement()
                               .withStatement("EXISTS(SELECT * FROM "Music" where Artist='No One You Know' and SongTitle='Call Me Today' and Awards is  MISSING)"));

        statements.add(new ParameterizedStatement()
                               .withStatement("INSERT INTO "Music" value {'Artist':'?','SongTitle':'?'}")
                               .withParameters(new AttributeValue("Acme Band"),new AttributeValue("Best Song")));

        statements.add(new ParameterizedStatement()
                               .withStatement("UPDATE "Music" SET AwardsWon=1 SET AwardDetail={'Grammys':[2020, 2018]}  where Artist='Acme Band' and SongTitle='PartiQL Rocks'"));

        return statements;
    }

    // Handles errors during ExecuteTransaction execution. Use recommendations in error messages below to add error handling specific to 
    // your application use-case.
    private static void handleExecuteTransactionErrors(Exception exception) {
        try {
            throw exception;
        } catch (TransactionCanceledException tce) {
            System.out.println("Transaction Cancelled, implies a client issue, fix before retrying. Error: " + tce.getErrorMessage());
        } catch (TransactionInProgressException tipe) {
            System.out.println("The transaction with the given request token is already in progress, consider changing " +
                "retry strategy for this type of error. Error: " + tipe.getErrorMessage());
        } catch (IdempotentParameterMismatchException ipme) {
            System.out.println("Request rejected because it was retried with a different payload but with a request token that was already used, " +
                "change request token for this payload to be accepted. Error: " + ipme.getErrorMessage());
        } catch (Exception e) {
            handleCommonErrors(e);
        }
    }

    private static void handleCommonErrors(Exception exception) {
        try {
            throw exception;
        } catch (InternalServerErrorException isee) {
            System.out.println("Internal Server Error, generally safe to retry with exponential back-off. Error: " + isee.getErrorMessage());
        } catch (RequestLimitExceededException rlee) {
            System.out.println("Throughput exceeds the current throughput limit for your account, increase account level throughput before " + 
                "retrying. Error: " + rlee.getErrorMessage());
        } catch (ProvisionedThroughputExceededException ptee) {
            System.out.println("Request rate is too high. If you're using a custom retry strategy make sure to retry with exponential back-off. " +
                "Otherwise consider reducing frequency of requests or increasing provisioned capacity for your table or secondary index. Error: " + 
                ptee.getErrorMessage());
        } catch (ResourceNotFoundException rnfe) {
            System.out.println("One of the tables was not found, verify table exists before retrying. Error: " + rnfe.getErrorMessage());
        } catch (AmazonServiceException ase) {
            System.out.println("An AmazonServiceException occurred, indicates that the request was correctly transmitted to the DynamoDB " + 
                "service, but for some reason, the service was not able to process it, and returned an error response instead. Investigate and " +
                "configure retry strategy. Error type: " + ase.getErrorType() + ". Error message: " + ase.getErrorMessage());
        } catch (AmazonClientException ace) {
            System.out.println("An AmazonClientException occurred, indicates that the client was unable to get a response from DynamoDB " +
                "service, or the client was unable to parse the response from the service. Investigate and configure retry strategy. "+
                "Error: " + ace.getMessage());
        } catch (Exception e) {
            System.out.println("An exception occurred, investigate and configure retry strategy. Error: " + e.getMessage());
        }
    }

}
```

------

Contoh berikut menunjukkan nilai pengembalian yang berbeda ketika DynamoDB membaca item dengan kondisi berbeda yang ditentukan dalam klausul WHERE.

------
#### [ AWS CLI ]

1. Simpan kode JSON berikut ke file bernama partiql.json.

   ```
   [
       // Item exists and projected attribute exists
       {
           "Statement": "SELECT * FROM "Music" WHERE Artist='No One You Know' and SongTitle='Call Me Today'"
       },
       // Item exists but projected attributes do not exist
       {
           "Statement": "SELECT non_existent_projected_attribute FROM "Music" WHERE Artist='No One You Know' and SongTitle='Call Me Today'"
       },
       // Item does not exist
       {
           "Statement": "SELECT * FROM "Music" WHERE Artist='No One I Know' and SongTitle='Call You Today'"
       }
   ]
   ```

1.  perintah berikut di prompt perintah.

   ```
   aws dynamodb execute-transaction --transact-statements  file://partiql.json
   ```

1. Respons berikut dikembalikan:

   ```
   {
       "Responses": [
           // Item exists and projected attribute exists
           {
               "Item": {
                   "Artist":{
                       "S": "No One You Know"
                   },
                   "SongTitle":{
                       "S": "Call Me Today"
                   }    
               }
           },
           // Item exists but projected attributes do not exist
           {
               "Item": {}
           },
           // Item does not exist
           {}
       ]
   }
   ```

------

# Menjalankan operasi batch dengan PartiQL untuk DynamoDB
<a name="ql-reference.multiplestatements.batching"></a>

Bagian ini menjelaskan cara menggunakan pernyataan batch dengan PartiQL untuk DynamoDB.

**catatan**  
Keseluruhan batch harus terdiri dari pernyataan baca atau pernyataan tulis; Anda tidak dapat mencampur keduanya dalam satu batch.
`BatchExecuteStatement` dan `BatchWriteItem` dapat melakukan tidak lebih dari 25 pernyataan per batch.
`BatchExecuteStatement`memanfaatkan `BatchGetItem` yang mengambil daftar kunci utama dalam pernyataan terpisah.

**Topics**
+ [Sintaks](#ql-reference.multiplestatements.batching.syntax)
+ [Parameter](#ql-reference.multiplestatements.batching.parameters)
+ [Contoh](#ql-reference.multiplestatements.batching.examples)

## Sintaks
<a name="ql-reference.multiplestatements.batching.syntax"></a>

```
[
  {
    "Statement": "SELECT pk FROM ProblemSet WHERE pk = 'p#9StkWHYTxm7x2AqSXcrfu7' AND sk = 'info'"
  },
  {
    "Statement": "SELECT pk FROM ProblemSet WHERE pk = 'p#isC2ChceGbxHgESc4szoTE' AND sk = 'info'"
  }
]
```

```
[
   {
      "Statement":" statement ",
      "Parameters":[
         {
            " parametertype " : " parametervalue "
         }, ...]
   } , ...
]
```

## Parameter
<a name="ql-reference.multiplestatements.batching.parameters"></a>

***statement***  
(Diperlukan) Pernyataan yang didukung PartiQL untuk DynamoDB.  
+ Keseluruhan batch harus terdiri dari pernyataan baca atau pernyataan tulis; Anda tidak dapat mencampur keduanya dalam satu batch.
+ `BatchExecuteStatement` dan `BatchWriteItem` dapat melakukan tidak lebih dari 25 pernyataan per batch.

***parametertype***  
(Opsional) Jenis DynamoDB, jika parameter digunakan saat menentukan pernyataan PartiQL.

***parametervalue***  
(Opsional) Nilai parameter jika parameter digunakan saat menentukan pernyataan PartiQL.

## Contoh
<a name="ql-reference.multiplestatements.batching.examples"></a>

------
#### [ AWS CLI ]

1. Simpan json berikut ke file bernama partiql.json

   ```
   [
      {
   	 "Statement": "INSERT INTO Music VALUE {'Artist':?,'SongTitle':?}",
   	  "Parameters": [{"S": "Acme Band"}, {"S": "Best Song"}]
   	},
   	{
   	 "Statement": "UPDATE Music SET AwardsWon=1, AwardDetail={'Grammys':[2020, 2018]} WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
       }
   ]
   ```

1. Jalankan perintah berikut di prompt perintah.

   ```
   aws dynamodb batch-execute-statement  --statements  file://partiql.json
   ```

------
#### [ Java ]

```
public class DynamoDBPartiqlBatch {

    public static void main(String[] args) {
        // Create the DynamoDB Client with the region you want
        AmazonDynamoDB dynamoDB = createDynamoDbClient("us-west-2");
        
        try {
            // Create BatchExecuteStatementRequest
            BatchExecuteStatementRequest batchExecuteStatementRequest = createBatchExecuteStatementRequest();
            BatchExecuteStatementResult batchExecuteStatementResult = dynamoDB.batchExecuteStatement(batchExecuteStatementRequest);
            System.out.println("BatchExecuteStatement successful.");
            // Handle batchExecuteStatementResult

        } catch (Exception e) {
            handleBatchExecuteStatementErrors(e);
        }
    }

    private static AmazonDynamoDB createDynamoDbClient(String region) {

        return AmazonDynamoDBClientBuilder.standard().withRegion(region).build();
    }

    private static BatchExecuteStatementRequest createBatchExecuteStatementRequest() {
        BatchExecuteStatementRequest request = new BatchExecuteStatementRequest();

        // Create statements
        List<BatchStatementRequest> statements = getPartiQLBatchStatements();

        request.setStatements(statements);
        return request;
    }

    private static List<BatchStatementRequest> getPartiQLBatchStatements() {
        List<BatchStatementRequest> statements = new ArrayList<BatchStatementRequest>();

        statements.add(new BatchStatementRequest()
                               .withStatement("INSERT INTO Music value {'Artist':'Acme Band','SongTitle':'PartiQL Rocks'}"));

        statements.add(new BatchStatementRequest()
                               .withStatement("UPDATE Music set AwardDetail.BillBoard=[2020] where Artist='Acme Band' and SongTitle='PartiQL Rocks'"));

        return statements;
    }

    // Handles errors during BatchExecuteStatement execution. Use recommendations in error messages below to add error handling specific to 
    // your application use-case.
    private static void handleBatchExecuteStatementErrors(Exception exception) {
        try {
            throw exception;
        } catch (Exception e) {
            // There are no API specific errors to handle for BatchExecuteStatement, common DynamoDB API errors are handled below
            handleCommonErrors(e);
        }
    }

    private static void handleCommonErrors(Exception exception) {
        try {
            throw exception;
        } catch (InternalServerErrorException isee) {
            System.out.println("Internal Server Error, generally safe to retry with exponential back-off. Error: " + isee.getErrorMessage());
        } catch (RequestLimitExceededException rlee) {
            System.out.println("Throughput exceeds the current throughput limit for your account, increase account level throughput before " + 
                "retrying. Error: " + rlee.getErrorMessage());
        } catch (ProvisionedThroughputExceededException ptee) {
            System.out.println("Request rate is too high. If you're using a custom retry strategy make sure to retry with exponential back-off. " +
                "Otherwise consider reducing frequency of requests or increasing provisioned capacity for your table or secondary index. Error: " + 
                ptee.getErrorMessage());
        } catch (ResourceNotFoundException rnfe) {
            System.out.println("One of the tables was not found, verify table exists before retrying. Error: " + rnfe.getErrorMessage());
        } catch (AmazonServiceException ase) {
            System.out.println("An AmazonServiceException occurred, indicates that the request was correctly transmitted to the DynamoDB " + 
                "service, but for some reason, the service was not able to process it, and returned an error response instead. Investigate and " +
                "configure retry strategy. Error type: " + ase.getErrorType() + ". Error message: " + ase.getErrorMessage());
        } catch (AmazonClientException ace) {
            System.out.println("An AmazonClientException occurred, indicates that the client was unable to get a response from DynamoDB " +
                "service, or the client was unable to parse the response from the service. Investigate and configure retry strategy. "+
                "Error: " + ace.getMessage());
        } catch (Exception e) {
            System.out.println("An exception occurred, investigate and configure retry strategy. Error: " + e.getMessage());
        }
    }

}
```

------

# Kebijakan keamanan IAM dengan PartiQL untuk DynamoDB
<a name="ql-iam"></a>

Izin berikut diperlukan:
+ Untuk membaca item menggunakan PartiQL untuk DynamoDB, Anda harus memiliki izin `dynamodb:PartiQLSelect` pada tabel atau indeks.
+ Untuk menyisipkan item menggunakan PartiQL untuk DynamoDB, Anda harus memiliki izin `dynamodb:PartiQLInsert` pada tabel atau indeks.
+ Untuk memperbarui item menggunakan PartiQL untuk DynamoDB, Anda harus memiliki izin `dynamodb:PartiQLUpdate` pada tabel atau indeks.
+ Untuk menghapus item menggunakan PartiQL untuk DynamoDB, Anda harus memiliki izin `dynamodb:PartiQLDelete` pada tabel atau indeks.

## Contoh: Izinkan semua PartiQL untuk pernyataan DynamoDB () di atas meja Select/Insert/Update/Delete
<a name="access-policy-ql-iam-example1"></a>

Kebijakan IAM berikut memberikan izin untuk menjalankan semua pernyataan PartiQL untuk DynamoDB pada tabel. 

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert",
            "dynamodb:PartiQLUpdate",
            "dynamodb:PartiQLDelete",
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ]
      }
   ]
}
```

------

## Contoh: Mengizinkan pernyataan pilih PartiQL untuk DynamoDB pada tabel
<a name="access-policy-ql-iam-example2"></a>

Kebijakan IAM berikut memberikan izin untuk menjalankan pernyataan `select` pada tabel tertentu.

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ]
      }
   ]
}
```

------

## Contoh: Mengizinkan PartiQL untuk pernyataan penyisipan DynamoDB pada indeks
<a name="access-policy-ql-iam-example3"></a>

Kebijakan IAM berikut memberikan izin untuk menjalankan pernyataan `insert` pada indeks tertentu. 

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music/index/index1"
         ]
      }
   ]
}
```

------

## Contoh: Mengizinkan PartiQL untuk pernyataan transaksional DynamoDB hanya pada tabel
<a name="access-policy-ql-iam-example4"></a>

Kebijakan IAM berikut memberikan izin untuk hanya menjalankan pernyataan transaksional pada tabel tertentu. 

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert",
            "dynamodb:PartiQLUpdate",
            "dynamodb:PartiQLDelete",
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ],
         "Condition":{
            "StringEquals":{
               "dynamodb:EnclosingOperation":[
                  "ExecuteTransaction"
               ]
            }
         }
      }
   ]
}
```

------

## Contoh: Mengizinkan PartiQL untuk pembacaan dan penulisan non-transaksional DynamoDB dan memblokir pernyataan transaksional pembacaan dan penulisan transaksional PartiQL pada tabel.
<a name="access-policy-ql-iam-example5"></a>

 Kebijakan IAM berikut memberikan izin untuk menjalankan PartiQL untuk pembacaan dan penulisan non-transaksional DynamoDB sambil memblokir PartiQL untuk pembacaan dan penulisan transaksional DynamoDB.

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Deny",
         "Action":[
            "dynamodb:PartiQLInsert",
            "dynamodb:PartiQLUpdate",
            "dynamodb:PartiQLDelete",
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ],
         "Condition":{
            "StringEquals":{
               "dynamodb:EnclosingOperation":[
                  "ExecuteTransaction"
               ]
            }
         }
      },
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert",
            "dynamodb:PartiQLUpdate",
            "dynamodb:PartiQLDelete",
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ]
      }
   ]
}
```

------

## Contoh: Mengizinkan pernyataan pilihan dan menolak pernyataan pemindaian tabel lengkap di PartiQL untuk DynamoDB
<a name="access-policy-ql-iam-example6"></a>

Kebijakan IAM berikut memberikan izin untuk menjalankan pernyataan `select` pada tabel tertentu sambil memblokir pernyataan `select` yang menghasilkan pemindaian tabel penuh.

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Deny",
         "Action":[
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/WatchList"
         ],
         "Condition":{
            "Bool":{
               "dynamodb:FullTableScan":[
                  "true"
               ]
            }
         }
      },
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/WatchList"
         ]
      }
   ]
}
```

------

# Bekerja dengan item: Java
<a name="JavaDocumentAPIItemCRUD"></a>

Anda dapat menggunakan AWS SDK untuk Java Document API untuk melakukan operasi membuat, membaca, memperbarui, dan menghapus (CRUD) pada item Amazon DynamoDB dalam tabel.

**catatan**  
SDK untuk Java juga menyediakan model persistensi objek, memungkinkan Anda memetakan kelas sisi klien ke tabel DynamoDB. Pendekatan ini dapat mengurangi jumlah kode yang harus Anda tulis. Untuk informasi selengkapnya, lihat [Java 1.x: Dinamo DBMapper](DynamoDBMapper.md).

Bagian ini berisi contoh Java untuk melakukan beberapa tindakan item Java Document API dan beberapa contoh kerja yang lengkap.

**Topics**
+ [Menempatkan item](#PutDocumentAPIJava)
+ [Mendapatkan item](#JavaDocumentAPIGetItem)
+ [Penulisan batch: Menempatkan dan menghapus beberapa item](#BatchWriteDocumentAPIJava)
+ [Batch get: Mendapatkan beberapa item](#JavaDocumentAPIBatchGetItem)
+ [Memperbarui Item](#JavaDocumentAPIItemUpdate)
+ [Menghapus item](#DeleteMidLevelJava)
+ [Contoh: Operasi CRUD menggunakan API AWS SDK untuk Java dokumen](JavaDocumentAPICRUDExample.md)
+ [Contoh: Operasi Batch menggunakan API AWS SDK untuk Java dokumen](batch-operation-document-api-java.md)
+ [Contoh: Menangani atribut tipe biner menggunakan API AWS SDK untuk Java dokumen](JavaDocumentAPIBinaryTypeExample.md)

## Menempatkan item
<a name="PutDocumentAPIJava"></a>

Metode `putItem` menyimpan item dalam tabel. Jika item ada, item tersebut akan menggantikan keseluruhan item. Alih-alih mengganti seluruh item, jika Anda hanya ingin memperbarui atribut tertentu, Anda dapat menggunakan metode `updateItem`. Untuk informasi selengkapnya, lihat [Memperbarui Item](#JavaDocumentAPIItemUpdate). 

------
#### [ Java v2 ]

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.PutItemResponse;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import java.util.HashMap;

/**
 * Before running this Java V2 code example, set up your development
 * environment, including your credentials.
 *
 * For more information, see the following documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 *
 * To place items into an Amazon DynamoDB table using the AWS SDK for Java V2,
 * its better practice to use the
 * Enhanced Client. See the EnhancedPutItem example.
 */
public class PutItem {
    public static void main(String[] args) {
        final String usage = """

                Usage:
                    <tableName> <key> <keyVal> <albumtitle> <albumtitleval> <awards> <awardsval> <Songtitle> <songtitleval>

                Where:
                    tableName - The Amazon DynamoDB table in which an item is placed (for example, Music3).
                    key - The key used in the Amazon DynamoDB table (for example, Artist).
                    keyval - The key value that represents the item to get (for example, Famous Band).
                    albumTitle - The Album title (for example, AlbumTitle).
                    AlbumTitleValue - The name of the album (for example, Songs About Life ).
                    Awards - The awards column (for example, Awards).
                    AwardVal - The value of the awards (for example, 10).
                    SongTitle - The song title (for example, SongTitle).
                    SongTitleVal - The value of the song title (for example, Happy Day).
                **Warning** This program will  place an item that you specify into a table!
                """;

        if (args.length != 9) {
            System.out.println(usage);
            System.exit(1);
        }

        String tableName = args[0];
        String key = args[1];
        String keyVal = args[2];
        String albumTitle = args[3];
        String albumTitleValue = args[4];
        String awards = args[5];
        String awardVal = args[6];
        String songTitle = args[7];
        String songTitleVal = args[8];

        Region region = Region.US_EAST_1;
        DynamoDbClient ddb = DynamoDbClient.builder()
                .region(region)
                .build();

        putItemInTable(ddb, tableName, key, keyVal, albumTitle, albumTitleValue, awards, awardVal, songTitle,
                songTitleVal);
        System.out.println("Done!");
        ddb.close();
    }

    public static void putItemInTable(DynamoDbClient ddb,
            String tableName,
            String key,
            String keyVal,
            String albumTitle,
            String albumTitleValue,
            String awards,
            String awardVal,
            String songTitle,
            String songTitleVal) {

        HashMap<String, AttributeValue> itemValues = new HashMap<>();
        itemValues.put(key, AttributeValue.builder().s(keyVal).build());
        itemValues.put(songTitle, AttributeValue.builder().s(songTitleVal).build());
        itemValues.put(albumTitle, AttributeValue.builder().s(albumTitleValue).build());
        itemValues.put(awards, AttributeValue.builder().s(awardVal).build());

        PutItemRequest request = PutItemRequest.builder()
                .tableName(tableName)
                .item(itemValues)
                .build();

        try {
            PutItemResponse response = ddb.putItem(request);
            System.out.println(tableName + " was successfully updated. The request id is "
                    + response.responseMetadata().requestId());

        } catch (ResourceNotFoundException e) {
            System.err.format("Error: The Amazon DynamoDB table \"%s\" can't be found.\n", tableName);
            System.err.println("Be sure that it exists and that you've typed its name correctly!");
            System.exit(1);
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
}
```

------
#### [ Java v1 ]

Ikuti langkah-langkah ini: 

1. Buat instans dari kelas `DynamoDB`.

1. Buat instans dari kelas `Table` untuk mewakili tabel yang ingin Anda gunakan.

1. Buat instans dari kelas `Item` untuk mewakili item baru. Anda harus menentukan kunci primer item baru dan atributnya.

1. Panggil metode `putItem` dari objek `Table` dengan menggunakan `Item` yang Anda buat pada langkah sebelumnya.

Contoh kode Java berikut menunjukkan tugas sebelumnya. Kode tersebut menulis item baru ke tabel `ProductCatalog`.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

// Build a list of related items
List<Number> relatedItems = new ArrayList<Number>();
relatedItems.add(341);
relatedItems.add(472);
relatedItems.add(649);

//Build a map of product pictures
Map<String, String> pictures = new HashMap<String, String>();
pictures.put("FrontView", "http://example.com/products/123_front.jpg");
pictures.put("RearView", "http://example.com/products/123_rear.jpg");
pictures.put("SideView", "http://example.com/products/123_left_side.jpg");

//Build a map of product reviews
Map<String, List<String>> reviews = new HashMap<String, List<String>>();

List<String> fiveStarReviews = new ArrayList<String>();
fiveStarReviews.add("Excellent! Can't recommend it highly enough!  Buy it!");
fiveStarReviews.add("Do yourself a favor and buy this");
reviews.put("FiveStar", fiveStarReviews);

List<String> oneStarReviews = new ArrayList<String>();
oneStarReviews.add("Terrible product!  Do not buy this.");
reviews.put("OneStar", oneStarReviews);

// Build the item
Item item = new Item()
    .withPrimaryKey("Id", 123)
    .withString("Title", "Bicycle 123")
    .withString("Description", "123 description")
    .withString("BicycleType", "Hybrid")
    .withString("Brand", "Brand-Company C")
    .withNumber("Price", 500)
    .withStringSet("Color",  new HashSet<String>(Arrays.asList("Red", "Black")))
    .withString("ProductCategory", "Bicycle")
    .withBoolean("InStock", true)
    .withNull("QuantityOnHand")
    .withList("RelatedItems", relatedItems)
    .withMap("Pictures", pictures)
    .withMap("Reviews", reviews);

// Write the item to the table
PutItemOutcome outcome = table.putItem(item);
```

Pada contoh sebelumnya, item memiliki atribut berupa skalar (`String`, `Number`, `Boolean`, `Null`), set (`String Set`), dan jenis dokumen (`List`, `Map`).

------

### Menentukan parameter opsional
<a name="PutItemJavaDocumentAPIOptions"></a>

Selain parameter yang diperlukan, Anda juga dapat menentukan parameter opsional untuk metode `putItem`. Misalnya, contoh kode Java berikut menggunakan parameter opsional untuk menentukan kondisi untuk mengunggah item. Jika kondisi yang Anda tentukan tidak terpenuhi, AWS SDK untuk Java lemparan a`ConditionalCheckFailedException`. Contoh kode menentukan parameter opsional berikut dalam metode `putItem`:
+ `ConditionExpression` yang mendefinisikan kondisi permintaan. Kode tersebut mendefinisikan kondisi bahwa item yang ada dengan kunci primer yang sama diganti hanya jika item tersebut memiliki atribut ISBN yang sama dengan nilai tertentu. 
+ Peta untuk `ExpressionAttributeValues` yang digunakan dalam kondisi tersebut. Dalam kasus ini, hanya ada satu substitusi yang diperlukan: placeholder `:val` dalam ekspresi kondisi diganti pada saat runtime dengan nilai ISBN aktual yang akan diperiksa.

Contoh berikut menambahkan item buku baru menggunakan parameter opsional.

**Example**  

```
Item item = new Item()
    .withPrimaryKey("Id", 104)
    .withString("Title", "Book 104 Title")
    .withString("ISBN", "444-4444444444")
    .withNumber("Price", 20)
    .withStringSet("Authors",
        new HashSet<String>(Arrays.asList("Author1", "Author2")));

Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val", "444-4444444444");

PutItemOutcome outcome = table.putItem(
    item,
    "ISBN = :val", // ConditionExpression parameter
    null,          // ExpressionAttributeNames parameter - we're not using it for this example
    expressionAttributeValues);
```

### PutItem dan dokumen JSON
<a name="PutItemJavaDocumentAPI.JSON"></a>

Anda dapat menyimpan dokumen JSON sebagai atribut dalam tabel DynamoDB. Untuk melakukannya, gunakan metode `withJSON` `Item`. Metode ini mengurai dokumen JSON dan memetakan setiap elemen untuk jenis daya DynamoDB asli.

Misalkan Anda ingin menyimpan dokumen JSON berikut, yang berisi vendor yang dapat memenuhi pesanan untuk produk tertentu.

**Example**  

```
{
    "V01": {
        "Name": "Acme Books",
        "Offices": [ "Seattle" ]
    },
    "V02": {
        "Name": "New Publishers, Inc.",
        "Offices": ["London", "New York"
        ]
    },
    "V03": {
        "Name": "Better Buy Books",
        "Offices": [ "Tokyo", "Los Angeles", "Sydney"
        ]
    }
}
```

Anda dapat menggunakan metode `withJSON` untuk menyimpan ini dalam tabel `ProductCatalog`, dalam atribut `Map` yang disebut `VendorInfo`. Contoh kode Java berikut mendemonstrasikan cara melakukannya.

```
// Convert the document into a String.  Must escape all double-quotes.
String vendorDocument = "{"
    + "    \"V01\": {"
    + "        \"Name\": \"Acme Books\","
    + "        \"Offices\": [ \"Seattle\" ]"
    + "    },"
    + "    \"V02\": {"
    + "        \"Name\": \"New Publishers, Inc.\","
    + "        \"Offices\": [ \"London\", \"New York\"" + "]" + "},"
    + "    \"V03\": {"
    + "        \"Name\": \"Better Buy Books\","
    +          "\"Offices\": [ \"Tokyo\", \"Los Angeles\", \"Sydney\""
    + "            ]"
    + "        }"
    + "    }";

Item item = new Item()
    .withPrimaryKey("Id", 210)
    .withString("Title", "Book 210 Title")
    .withString("ISBN", "210-2102102102")
    .withNumber("Price", 30)
    .withJSON("VendorInfo", vendorDocument);

PutItemOutcome outcome = table.putItem(item);
```

## Mendapatkan item
<a name="JavaDocumentAPIGetItem"></a>

Untuk mengambil satu item, gunakan metode `getItem` dari objek `Table`. Ikuti langkah-langkah ini: 

1. Buat instans dari kelas `DynamoDB`.

1. Buat instans dari kelas `Table` untuk mewakili tabel yang ingin Anda gunakan.

1. Panggil metode `getItem` dari instans `Table`. Anda harus menentukan kunci item primer yang ingin Anda ambil.

Contoh kode Java berikut mendemonstrasikan langkah sebelumnya. Kode mendapatkan item yang memiliki kunci partisi yang ditentukan.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

Item item = table.getItem("Id", 210);
```

### Menentukan parameter opsional
<a name="GetItemJavaDocumentAPIOptions"></a>

Selain parameter yang diperlukan, Anda juga dapat menentukan parameter opsional untuk metode `getItem`. Misalnya, contoh kode Java berikut menggunakan metode opsional untuk mengambil hanya daftar atribut tertentu dan menentukan bacaan sangat konsisten. (Untuk mempelajari selengkapnya tentang konsistensi baca, lihat [DynamoDB membaca konsistensi](HowItWorks.ReadConsistency.md).)

Anda dapat menggunakan `ProjectionExpression` untuk mengambil hanya atribut atau elemen tertentu, bukan seluruh item. `ProjectionExpression` dapat menentukan tingkat atas atau atribut bersarang menggunakan jalur dokumen. Untuk informasi selengkapnya, lihat [Menggunakan ekspresi proyeksi di DynamoDB](Expressions.ProjectionExpressions.md).

Parameter dari metode `getItem` tidak membiarkan Anda menentukan konsistensi baca. Namun, Anda dapat membuat `GetItemSpec`, yang menyediakan akses penuh ke semua input ke operasi `GetItem` tingkat rendah. Contoh kode berikut membuat `GetItemSpec` dan menggunakan spesifikasi tersebut sebagai input untuk metode `getItem`.

**Example**  

```
GetItemSpec spec = new GetItemSpec()
    .withPrimaryKey("Id", 206)
    .withProjectionExpression("Id, Title, RelatedItems[0], Reviews.FiveStar")
    .withConsistentRead(true);

Item item = table.getItem(spec);

System.out.println(item.toJSONPretty());
```

 Untuk mencetak `Item` dalam format yang dapat dibaca manusia, gunakan metode `toJSONPretty`. Output dari contoh sebelumnya terlihat seperti berikut ini.

```
{
  "RelatedItems" : [ 341 ],
  "Reviews" : {
    "FiveStar" : [ "Excellent! Can't recommend it highly enough! Buy it!", "Do yourself a favor and buy this" ]
  },
  "Id" : 123,
  "Title" : "20-Bicycle 123"
}
```

### GetItem dan dokumen JSON
<a name="GetItemJavaDocumentAPI.JSON"></a>

Di bagian [PutItem dan dokumen JSON](#PutItemJavaDocumentAPI.JSON), Anda menyimpan dokumen JSON dalam atribut `Map` yang disebut `VendorInfo`. Anda dapat menggunakan metode `getItem` untuk mengambil seluruh dokumen dalam format JSON. Selain itu, Anda dapat menggunakan notasi jalur dokumen untuk mengambil hanya beberapa elemen dalam dokumen. Contoh kode Java berikut mendemonstrasikan teknik ini.

```
GetItemSpec spec = new GetItemSpec()
    .withPrimaryKey("Id", 210);

System.out.println("All vendor info:");
spec.withProjectionExpression("VendorInfo");
System.out.println(table.getItem(spec).toJSON());

System.out.println("A single vendor:");
spec.withProjectionExpression("VendorInfo.V03");
System.out.println(table.getItem(spec).toJSON());

System.out.println("First office location for this vendor:");
spec.withProjectionExpression("VendorInfo.V03.Offices[0]");
System.out.println(table.getItem(spec).toJSON());
```

Output dari contoh sebelumnya terlihat seperti berikut ini.

```
All vendor info:
{"VendorInfo":{"V03":{"Name":"Better Buy Books","Offices":["Tokyo","Los Angeles","Sydney"]},"V02":{"Name":"New Publishers, Inc.","Offices":["London","New York"]},"V01":{"Name":"Acme Books","Offices":["Seattle"]}}}
A single vendor:
{"VendorInfo":{"V03":{"Name":"Better Buy Books","Offices":["Tokyo","Los Angeles","Sydney"]}}}
First office location for a single vendor:
{"VendorInfo":{"V03":{"Offices":["Tokyo"]}}}
```

**catatan**  
Anda dapat menggunakan metode `toJSON` untuk mengonversi item apa pun (atau atributnya) ke string berformat JSON. Kode berikut mengambil beberapa atribut tingkat atas dan bertingkat serta mencetak hasilnya sebagai JSON.  

```
GetItemSpec spec = new GetItemSpec()
    .withPrimaryKey("Id", 210)
    .withProjectionExpression("VendorInfo.V01, Title, Price");

Item item = table.getItem(spec);
System.out.println(item.toJSON());
```
Output-nya akan terlihat seperti berikut.  

```
{"VendorInfo":{"V01":{"Name":"Acme Books","Offices":["Seattle"]}},"Price":30,"Title":"Book 210 Title"}
```

## Penulisan batch: Menempatkan dan menghapus beberapa item
<a name="BatchWriteDocumentAPIJava"></a>

*Penulisan batch* merujuk pada penempatan dan penghapusan beberapa item dalam satu batch. Metode `batchWriteItem` memungkinkan Anda untuk memasukkan dan menghapus beberapa item dari satu atau lebih tabel dalam satu panggilan. Berikut ini adalah langkah-langkah untuk menempatkan atau menghapus beberapa item menggunakan AWS SDK untuk Java Document API.

1. Buat instans dari kelas `DynamoDB`.

1. Buat instans dari kelas `TableWriteItems` yang menjelaskan semua operasi put dan hapus untuk tabel. Jika Anda ingin menulis ke beberapa tabel dalam satu operasi penulisan batch, Anda harus membuat satu instans `TableWriteItems` per tabel.

1. Jalankan metode `batchWriteItem` dengan menyediakan objek `TableWriteItems` yang Anda buat pada langkah sebelumnya. 

1. Proses responsnya. Anda harus memeriksa apakah ada item permintaan yang belum diproses yang dikembalikan sebagai respons. Hal ini dapat terjadi jika Anda mencapai kuota throughput yang disediakan atau kesalahan sementara lainnya. Selain itu, DynamoDB membatasi ukuran permintaan dan jumlah operasi yang dapat Anda tentukan dalam permintaan. Jika Anda melebihi batas ini, DynamoDB menolak permintaan tersebut. Untuk informasi selengkapnya, lihat [Kuota di Amazon DynamoDB](ServiceQuotas.md). 

Contoh kode Java berikut mendemonstrasikan langkah sebelumnya. Contoh tersebut melakukan operasi `batchWriteItem` pada dua tabel: `Forum` dan `Thread`. Objek `TableWriteItems` yang sesuai menentukan tindakan berikut:
+ Tempatkan satu item dalam tabel `Forum`.
+ Tempatkan dan hapus satu item dalam tabel `Thread`.

Kode kemudian menjalankan `batchWriteItem` untuk melakukan operasi.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

TableWriteItems forumTableWriteItems = new TableWriteItems("Forum")
    .withItemsToPut(
        new Item()
            .withPrimaryKey("Name", "Amazon RDS")
            .withNumber("Threads", 0));

TableWriteItems threadTableWriteItems = new TableWriteItems("Thread")
    .withItemsToPut(
        new Item()
            .withPrimaryKey("ForumName","Amazon RDS","Subject","Amazon RDS Thread 1")
    .withHashAndRangeKeysToDelete("ForumName","Some partition key value", "Amazon S3", "Some sort key value");

BatchWriteItemOutcome outcome = dynamoDB.batchWriteItem(forumTableWriteItems, threadTableWriteItems);

// Code for checking unprocessed items is omitted in this example
```

Untuk contoh pekerjaan, lihat [Contoh: Operasi penulisan Batch menggunakan API AWS SDK untuk Java dokumen](batch-operation-document-api-java.md#JavaDocumentAPIBatchWrite). 

## Batch get: Mendapatkan beberapa item
<a name="JavaDocumentAPIBatchGetItem"></a>

Metode `batchGetItem` memungkinkan Anda mengambil beberapa item dari satu atau lebih tabel. Untuk mengambil satu item, Anda dapat menggunakan metode `getItem`. 

Ikuti langkah-langkah ini: 

1. Buat instans dari kelas `DynamoDB`.

1. Buat instans dari kelas `TableKeysAndAttributes` yang menjelaskan daftar nilai kunci primer untuk mengambil dari tabel. Jika Anda ingin membaca dari beberapa tabel dalam satu operasi penulisan batch, Anda harus membuat satu instans `TableKeysAndAttributes` per tabel.

1. Jalankan metode `batchGetItem` dengan menyediakan objek `TableKeysAndAttributes` yang Anda buat pada langkah sebelumnya.

Contoh kode Java berikut mendemonstrasikan langkah sebelumnya. Contoh tersebut mengambil dua item dari tabel `Forum` dan tiga item dari tabel `Thread`.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

    TableKeysAndAttributes forumTableKeysAndAttributes = new TableKeysAndAttributes(forumTableName);
    forumTableKeysAndAttributes.addHashOnlyPrimaryKeys("Name",
    "Amazon S3",
    "Amazon DynamoDB");

TableKeysAndAttributes threadTableKeysAndAttributes = new TableKeysAndAttributes(threadTableName);
threadTableKeysAndAttributes.addHashAndRangePrimaryKeys("ForumName", "Subject",
    "Amazon DynamoDB","DynamoDB Thread 1",
    "Amazon DynamoDB","DynamoDB Thread 2",
    "Amazon S3","S3 Thread 1");

BatchGetItemOutcome outcome = dynamoDB.batchGetItem(
    forumTableKeysAndAttributes, threadTableKeysAndAttributes);

for (String tableName : outcome.getTableItems().keySet()) {
    System.out.println("Items in table " + tableName);
    List<Item> items = outcome.getTableItems().get(tableName);
    for (Item item : items) {
        System.out.println(item);
    }
}
```

### Menentukan parameter opsional
<a name="BatchGetItemJavaDocumentAPIOptions"></a>

Bersamaan dengan parameter yang diperlukan, Anda juga dapat menentukan parameter opsional saat menggunakan `batchGetItem`. Misalnya, Anda dapat memberikan `ProjectionExpression` dengan setiap `TableKeysAndAttributes` yang Anda tentukan. Hal ini memungkinkan Anda menentukan atribut yang ingin Anda ambil dari tabel.

Contoh kode berikut mengambil dua item dari tabel `Forum`. Parameter `withProjectionExpression` menentukan bahwa hanya atribut `Threads` yang akan diambil.

**Example**  

```
TableKeysAndAttributes forumTableKeysAndAttributes = new TableKeysAndAttributes("Forum")
    .withProjectionExpression("Threads");

forumTableKeysAndAttributes.addHashOnlyPrimaryKeys("Name",
    "Amazon S3",
    "Amazon DynamoDB");

BatchGetItemOutcome outcome = dynamoDB.batchGetItem(forumTableKeysAndAttributes);
```

## Memperbarui Item
<a name="JavaDocumentAPIItemUpdate"></a>

Metode `updateItem` dari objek `Table` dapat memperbarui nilai atribut yang ada, menambahkan atribut baru, atau menghapus atribut dari item yang ada. 

Metode `updateItem` berperilaku sebagai berikut:
+ Jika item tidak ada (tidak ada item dalam tabel dengan kunci primer yang ditentukan), `updateItem` menambahkan item baru ke tabel.
+ Jika item ada, `updateItem` melakukan pembaruan seperti yang ditentukan oleh parameter `UpdateExpression`.

**catatan**  
Hal ini juga memungkinkan untuk "memperbarui" item menggunakan `putItem`. Misalnya, jika Anda memanggil `putItem` untuk menambahkan item ke tabel, tetapi sudah ada item dengan kunci primer yang ditentukan, `putItem` akan menggantikan seluruh item. Jika ada atribut dalam item yang ada yang tidak ditentukan dalam input, `putItem` akan menghapus atribut tersebut dari item.  
Secara umum, sebaiknya gunakan `updateItem` setiap kali Anda ingin memodifikasi atribut item. Metode `updateItem` hanya memodifikasi atribut item yang Anda tentukan dalam input, dan atribut lainnya dalam item tidak berubah.

Ikuti langkah-langkah ini: 

1. Buat instans dari kelas `Table` untuk mewakili tabel yang ingin Anda gunakan.

1. Panggil metode `updateTable` dari instans `Table`. Anda harus menentukan kunci primer dari item yang ingin Anda ambil, bersama dengan `UpdateExpression` yang menjelaskan atribut untuk memodifikasi dan cara memodifikasinya.

Contoh kode Java berikut menunjukkan tugas sebelumnya. Kode tersebut memperbarui item buku dalam tabel `ProductCatalog`. Contoh tersebut menambahkan penulis baru ke set `Authors`, dan menghapus atribut `ISBN` yang ada. Contoh tersebut juga mengurangi harga sebanyak satu.

Peta `ExpressionAttributeValues` digunakan dalam `UpdateExpression`. Placeholder `:val1` dan `:val2` diganti pada saat runtime dengan nilai aktual untuk `Authors` dan `Price`.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#A", "Authors");
expressionAttributeNames.put("#P", "Price");
expressionAttributeNames.put("#I", "ISBN");

Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val1",
    new HashSet<String>(Arrays.asList("Author YY","Author ZZ")));
expressionAttributeValues.put(":val2", 1);   //Price

UpdateItemOutcome outcome =  table.updateItem(
    "Id",          // key attribute name
    101,           // key attribute value
    "add #A :val1 set #P = #P - :val2 remove #I", // UpdateExpression
    expressionAttributeNames,
    expressionAttributeValues);
```

### Menentukan parameter opsional
<a name="UpdateItemJavaDocumentAPIOptions"></a>

Bersamaan dengan parameter yang diperlukan, Anda juga dapat menentukan parameter opsional untuk metode `updateItem`, termasuk kondisi yang harus dipenuhi agar pembaruan bisa terjadi. Jika kondisi yang Anda tentukan tidak terpenuhi, AWS SDK untuk Java lemparan a`ConditionalCheckFailedException`. Misalnya, contoh kode Java berikut memperbarui harga item buku secara kondisional menjadi 25. Ini menentukan pernyataan `ConditionExpression` bahwa harga harus diperbarui hanya jika harga saat ini adalah 20.

**Example**  

```
Table table = dynamoDB.getTable("ProductCatalog");

Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#P", "Price");

Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val1", 25);  // update Price to 25...
expressionAttributeValues.put(":val2", 20);  //...but only if existing Price is 20

UpdateItemOutcome outcome = table.updateItem(
    new PrimaryKey("Id",101),
    "set #P = :val1", // UpdateExpression
    "#P = :val2",     // ConditionExpression
    expressionAttributeNames,
    expressionAttributeValues);
```

### Penghitung atom
<a name="AtomicCounterJavaDocumentAPI"></a>

Anda dapat menggunakan `updateItem` untuk mengimplementasi penghitung atom, di mana Anda menambahkan atau mengurangi nilai atribut yang ada tanpa mengganggu permintaan tulis lainnya. Untuk kenaikan penghitung atom, gunakan `UpdateExpression` dengan tindakan `set` untuk menambahkan nilai numerik ke atribut jenis `Number` yang ada.

Contoh berikut menunjukkan hal ini, menambahkan satu atribut `Quantity`. Hal ini juga menunjukkan penggunaan parameter `ExpressionAttributeNames` dalam `UpdateExpression`.

```
Table table = dynamoDB.getTable("ProductCatalog");

Map<String,String> expressionAttributeNames = new HashMap<String,String>();
expressionAttributeNames.put("#p", "PageCount");

Map<String,Object> expressionAttributeValues = new HashMap<String,Object>();
expressionAttributeValues.put(":val", 1);

UpdateItemOutcome outcome = table.updateItem(
    "Id", 121,
    "set #p = #p + :val",
    expressionAttributeNames,
    expressionAttributeValues);
```

## Menghapus item
<a name="DeleteMidLevelJava"></a>

Metode `deleteItem` menghapus item dari tabel. Anda harus menyediakan kunci item primer yang ingin Anda hapus.

Ikuti langkah-langkah ini: 

1. Buat instans dari klien `DynamoDB`.

1. Panggil metode `deleteItem` dengan menyediakan kunci item yang ingin Anda hapus. 

Contoh Java berikut menunjukkan tugas ini.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

DeleteItemOutcome outcome = table.deleteItem("Id", 101);
```

### Menentukan parameter opsional
<a name="DeleteItemJavaDocumentAPIOptions"></a>

Anda dapat menentukan parameter opsional untuk `deleteItem`. Misalnya, contoh kode Java berikut menentukan `ConditionExpression`, yang menyatakan bahwa item buku dalam `ProductCatalog` hanya dapat dihapus jika buku ini tidak lagi dalam publikasi (atribut `InPublication` adalah salah).

**Example**  

```
Map<String,Object> expressionAttributeValues = new HashMap<String,Object>();
expressionAttributeValues.put(":val", false);

DeleteItemOutcome outcome = table.deleteItem("Id",103,
    "InPublication = :val",
    null, // ExpressionAttributeNames - not used in this example
    expressionAttributeValues);
```

# Contoh: Operasi CRUD menggunakan API AWS SDK untuk Java dokumen
<a name="JavaDocumentAPICRUDExample"></a>

Contoh kode berikut menunjukkan operasi CRUD pada item Amazon DynamoDB. Contohnya membuat item, mengambilnya, melakukan berbagai pembaruan, dan akhirnya menghapus item tersebut.

**catatan**  
SDK untuk Java juga menyediakan model persistensi objek, memungkinkan Anda memetakan kelas sisi klien ke tabel DynamoDB. Pendekatan ini dapat mengurangi jumlah kode yang harus Anda tulis. Untuk informasi selengkapnya, lihat [Java 1.x: Dinamo DBMapper](DynamoDBMapper.md).

**catatan**  
Contoh kode ini mengasumsikan bahwa Anda telah memuat data ke DynamoDB untuk akun Anda dengan mengikuti petunjuk di bagian [Membuat tabel dan memuat data untuk contoh kode di DynamoDB](SampleData.md).  
Untuk step-by-step instruksi untuk menjalankan contoh berikut, lihat[Contoh kode Java](CodeSamples.Java.md).

```
package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DeleteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.UpdateItemOutcome;
import com.amazonaws.services.dynamodbv2.document.spec.DeleteItemSpec;
import com.amazonaws.services.dynamodbv2.document.spec.UpdateItemSpec;
import com.amazonaws.services.dynamodbv2.document.utils.NameMap;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.ReturnValue;

public class DocumentAPIItemCRUDExample {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String tableName = "ProductCatalog";

    public static void main(String[] args) throws IOException {

        createItems();

        retrieveItem();

        // Perform various updates.
        updateMultipleAttributes();
        updateAddNewAttribute();
        updateExistingAttributeConditionally();

        // Delete the item.
        deleteItem();

    }

    private static void createItems() {

        Table table = dynamoDB.getTable(tableName);
        try {

            Item item = new Item().withPrimaryKey("Id", 120).withString("Title", "Book 120 Title")
                    .withString("ISBN", "120-1111111111")
                    .withStringSet("Authors", new HashSet<String>(Arrays.asList("Author12", "Author22")))
                    .withNumber("Price", 20).withString("Dimensions", "8.5x11.0x.75").withNumber("PageCount", 500)
                    .withBoolean("InPublication", false).withString("ProductCategory", "Book");
            table.putItem(item);

            item = new Item().withPrimaryKey("Id", 121).withString("Title", "Book 121 Title")
                    .withString("ISBN", "121-1111111111")
                    .withStringSet("Authors", new HashSet<String>(Arrays.asList("Author21", "Author 22")))
                    .withNumber("Price", 20).withString("Dimensions", "8.5x11.0x.75").withNumber("PageCount", 500)
                    .withBoolean("InPublication", true).withString("ProductCategory", "Book");
            table.putItem(item);

        } catch (Exception e) {
            System.err.println("Create items failed.");
            System.err.println(e.getMessage());

        }
    }

    private static void retrieveItem() {
        Table table = dynamoDB.getTable(tableName);

        try {

            Item item = table.getItem("Id", 120, "Id, ISBN, Title, Authors", null);

            System.out.println("Printing item after retrieving it....");
            System.out.println(item.toJSONPretty());

        } catch (Exception e) {
            System.err.println("GetItem failed.");
            System.err.println(e.getMessage());
        }

    }

    private static void updateAddNewAttribute() {
        Table table = dynamoDB.getTable(tableName);

        try {

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 121)
                    .withUpdateExpression("set #na = :val1").withNameMap(new NameMap().with("#na", "NewAttribute"))
                    .withValueMap(new ValueMap().withString(":val1", "Some value"))
                    .withReturnValues(ReturnValue.ALL_NEW);

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after adding new attribute...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Failed to add new attribute in " + tableName);
            System.err.println(e.getMessage());
        }
    }

    private static void updateMultipleAttributes() {

        Table table = dynamoDB.getTable(tableName);

        try {

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 120)
                    .withUpdateExpression("add #a :val1 set #na=:val2")
                    .withNameMap(new NameMap().with("#a", "Authors").with("#na", "NewAttribute"))
                    .withValueMap(
                            new ValueMap().withStringSet(":val1", "Author YY", "Author ZZ").withString(":val2",
                                    "someValue"))
                    .withReturnValues(ReturnValue.ALL_NEW);

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after multiple attribute update...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Failed to update multiple attributes in " + tableName);
            System.err.println(e.getMessage());

        }
    }

    private static void updateExistingAttributeConditionally() {

        Table table = dynamoDB.getTable(tableName);

        try {

            // Specify the desired price (25.00) and also the condition (price =
            // 20.00)

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 120)
                    .withReturnValues(ReturnValue.ALL_NEW).withUpdateExpression("set #p = :val1")
                    .withConditionExpression("#p = :val2").withNameMap(new NameMap().with("#p", "Price"))
                    .withValueMap(new ValueMap().withNumber(":val1", 25).withNumber(":val2", 20));

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after conditional update to new attribute...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Error updating item in " + tableName);
            System.err.println(e.getMessage());
        }
    }

    private static void deleteItem() {

        Table table = dynamoDB.getTable(tableName);

        try {

            DeleteItemSpec deleteItemSpec = new DeleteItemSpec().withPrimaryKey("Id", 120)
                    .withConditionExpression("#ip = :val").withNameMap(new NameMap().with("#ip", "InPublication"))
                    .withValueMap(new ValueMap().withBoolean(":val", false)).withReturnValues(ReturnValue.ALL_OLD);

            DeleteItemOutcome outcome = table.deleteItem(deleteItemSpec);

            // Check the response.
            System.out.println("Printing item that was deleted...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Error deleting item in " + tableName);
            System.err.println(e.getMessage());
        }
    }
}
```

# Contoh: Operasi Batch menggunakan API AWS SDK untuk Java dokumen
<a name="batch-operation-document-api-java"></a>

Bagian ini memberikan contoh operasi batch write dan batch get di Amazon DynamoDB menggunakan AWS SDK untuk Java Document API.

**catatan**  
SDK untuk Java juga menyediakan model persistensi objek, memungkinkan Anda memetakan kelas sisi klien ke tabel DynamoDB. Pendekatan ini dapat mengurangi jumlah kode yang harus Anda tulis. Untuk informasi selengkapnya, lihat [Java 1.x: Dinamo DBMapper](DynamoDBMapper.md).

**Topics**
+ [Contoh: Operasi penulisan Batch menggunakan API AWS SDK untuk Java dokumen](#JavaDocumentAPIBatchWrite)
+ [Contoh: Operasi batch get menggunakan API AWS SDK untuk Java dokumen](#JavaDocumentAPIBatchGet)

## Contoh: Operasi penulisan Batch menggunakan API AWS SDK untuk Java dokumen
<a name="JavaDocumentAPIBatchWrite"></a>

Contoh kode Java berikut menggunakan metode `batchWriteItem` untuk melakukan operasi put dan delete berikut:
+ Tempatkan satu item dalam tabel `Forum`.
+ Tempatkan satu item dan hapus satu item dari tabel `Thread`. 

Anda dapat menentukan sejumlah permintaan put dan delete terhadap satu atau beberapa tabel saat membuat permintaan batch write Anda. Namun, `batchWriteItem` membatasi ukuran permintaan penulisan batch dan jumlah operasi put dan delete dalam satu operasi penulisan batch. Jika permintaan Anda melebihi batas ini, permintaan Anda ditolak. Jika tabel Anda tidak memiliki cukup throughput yang disediakan untuk melayani permintaan ini, item permintaan yang belum diproses akan dikembalikan sebagai respons. 

Contoh berikut memeriksa respons untuk melihat apakah ada item permintaan yang belum diproses. Jika ya, contoh tersebut akan mengulang kembali dan mengirim ulang permintaan `batchWriteItem` dengan item yang belum diproses dalam permintaan tersebut. Jika Anda mengikuti contoh dalam panduan ini, Anda seharusnya sudah membuat `Forum` dan `Thread` tabel. Anda juga dapat membuat tabel ini dan mengunggah data sampel secara terprogram. Untuk informasi selengkapnya, lihat [Membuat tabel contoh dan mengunggah data menggunakan AWS SDK untuk Java](AppendixSampleDataCodeJava.md).

Untuk step-by-step petunjuk pengujian sampel berikut, lihat[Contoh kode Java](CodeSamples.Java.md). 

**Example**  

```
package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.BatchWriteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.TableWriteItems;
import com.amazonaws.services.dynamodbv2.model.WriteRequest;

public class DocumentAPIBatchWrite {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String forumTableName = "Forum";
    static String threadTableName = "Thread";

    public static void main(String[] args) throws IOException {

        writeMultipleItemsBatchWrite();

    }

    private static void writeMultipleItemsBatchWrite() {
        try {

            // Add a new item to Forum
            TableWriteItems forumTableWriteItems = new TableWriteItems(forumTableName) // Forum
                    .withItemsToPut(new Item().withPrimaryKey("Name", "Amazon RDS").withNumber("Threads", 0));

            // Add a new item, and delete an existing item, from Thread
            // This table has a partition key and range key, so need to specify
            // both of them
            TableWriteItems threadTableWriteItems = new TableWriteItems(threadTableName)
                    .withItemsToPut(
                            new Item().withPrimaryKey("ForumName", "Amazon RDS", "Subject", "Amazon RDS Thread 1")
                                    .withString("Message", "ElastiCache Thread 1 message")
                                    .withStringSet("Tags", new HashSet<String>(Arrays.asList("cache", "in-memory"))))
                    .withHashAndRangeKeysToDelete("ForumName", "Subject", "Amazon S3", "S3 Thread 100");

            System.out.println("Making the request.");
            BatchWriteItemOutcome outcome = dynamoDB.batchWriteItem(forumTableWriteItems, threadTableWriteItems);

            do {

                // Check for unprocessed keys which could happen if you exceed
                // provisioned throughput

                Map<String, List<WriteRequest>> unprocessedItems = outcome.getUnprocessedItems();

                if (outcome.getUnprocessedItems().size() == 0) {
                    System.out.println("No unprocessed items found");
                } else {
                    System.out.println("Retrieving the unprocessed items");
                    outcome = dynamoDB.batchWriteItemUnprocessed(unprocessedItems);
                }

            } while (outcome.getUnprocessedItems().size() > 0);

        } catch (Exception e) {
            System.err.println("Failed to retrieve items: ");
            e.printStackTrace(System.err);
        }

    }

}
```

## Contoh: Operasi batch get menggunakan API AWS SDK untuk Java dokumen
<a name="JavaDocumentAPIBatchGet"></a>

Contoh kode Java berikut menggunakan metode `batchGetItem` untuk mengambil beberapa item dari tabel `Forum` dan `Thread`. `BatchGetItemRequest` menentukan nama tabel dan daftar kunci untuk setiap item yang akan didapatkan. Contoh tersebut memproses respons dengan mencetak item yang diambil.

**catatan**  
Contoh kode ini mengasumsikan bahwa Anda telah memuat data ke DynamoDB untuk akun Anda dengan mengikuti petunjuk di bagian [Membuat tabel dan memuat data untuk contoh kode di DynamoDB](SampleData.md).  
Untuk step-by-step instruksi untuk menjalankan contoh berikut, lihat[Contoh kode Java](CodeSamples.Java.md).

**Example**  

```
package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.BatchGetItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.TableKeysAndAttributes;
import com.amazonaws.services.dynamodbv2.model.KeysAndAttributes;

public class DocumentAPIBatchGet {
    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String forumTableName = "Forum";
    static String threadTableName = "Thread";

    public static void main(String[] args) throws IOException {
        retrieveMultipleItemsBatchGet();
    }

    private static void retrieveMultipleItemsBatchGet() {

        try {

            TableKeysAndAttributes forumTableKeysAndAttributes = new TableKeysAndAttributes(forumTableName);
            // Add a partition key
            forumTableKeysAndAttributes.addHashOnlyPrimaryKeys("Name", "Amazon S3", "Amazon DynamoDB");

            TableKeysAndAttributes threadTableKeysAndAttributes = new TableKeysAndAttributes(threadTableName);
            // Add a partition key and a sort key
            threadTableKeysAndAttributes.addHashAndRangePrimaryKeys("ForumName", "Subject", "Amazon DynamoDB",
                    "DynamoDB Thread 1", "Amazon DynamoDB", "DynamoDB Thread 2", "Amazon S3", "S3 Thread 1");

            System.out.println("Making the request.");

            BatchGetItemOutcome outcome = dynamoDB.batchGetItem(forumTableKeysAndAttributes,
                    threadTableKeysAndAttributes);

            Map<String, KeysAndAttributes> unprocessed = null;

            do {
                for (String tableName : outcome.getTableItems().keySet()) {
                    System.out.println("Items in table " + tableName);
                    List<Item> items = outcome.getTableItems().get(tableName);
                    for (Item item : items) {
                        System.out.println(item.toJSONPretty());
                    }
                }

                // Check for unprocessed keys which could happen if you exceed
                // provisioned
                // throughput or reach the limit on response size.
                unprocessed = outcome.getUnprocessedKeys();

                if (unprocessed.isEmpty()) {
                    System.out.println("No unprocessed keys found");
                } else {
                    System.out.println("Retrieving the unprocessed keys");
                    outcome = dynamoDB.batchGetItemUnprocessed(unprocessed);
                }

            } while (!unprocessed.isEmpty());

        } catch (Exception e) {
            System.err.println("Failed to retrieve items.");
            System.err.println(e.getMessage());
        }

    }

}
```

# Contoh: Menangani atribut tipe biner menggunakan API AWS SDK untuk Java dokumen
<a name="JavaDocumentAPIBinaryTypeExample"></a>

Contoh kode Java berikut menggambarkan penanganan atribut jenis biner. Contoh tersebut menambahkan item ke tabel `Reply`. Item termasuk atribut jenis biner (`ExtendedMessage`) yang menyimpan data terkompresi. Contoh tersebut kemudian mengambil item dan mencetak semua nilai atribut. Sebagai ilustrasi, contoh menggunakan kelas `GZIPOutputStream` untuk mengompresi aliran sampel dan menetapkannya ke atribut `ExtendedMessage`. Ketika atribut binari diambil, atribut didekompresi menggunakan kelas `GZIPInputStream`. 

**catatan**  
SDK untuk Java juga menyediakan model persistensi objek, memungkinkan Anda memetakan kelas sisi klien ke tabel DynamoDB. Pendekatan ini dapat mengurangi jumlah kode yang harus Anda tulis. Untuk informasi selengkapnya, lihat [Java 1.x: Dinamo DBMapper](DynamoDBMapper.md).

Jika Anda mengikuti bagian [Membuat tabel dan memuat data untuk contoh kode di DynamoDB](SampleData.md), semestinya Anda telah membuat tabel `Reply`. Anda juga dapat membuat tabel ini secara terprogram. Untuk informasi selengkapnya, lihat [Membuat tabel contoh dan mengunggah data menggunakan AWS SDK untuk Java](AppendixSampleDataCodeJava.md).

Untuk step-by-step petunjuk pengujian sampel berikut, lihat[Contoh kode Java](CodeSamples.Java.md). 

**Example**  

```
package com.amazonaws.codesamples.document;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.GetItemSpec;

public class DocumentAPIItemBinaryExample {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String tableName = "Reply";
    static SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

    public static void main(String[] args) throws IOException {
        try {

            // Format the primary key values
            String threadId = "Amazon DynamoDB#DynamoDB Thread 2";

            dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
            String replyDateTime = dateFormatter.format(new Date());

            // Add a new reply with a binary attribute type
            createItem(threadId, replyDateTime);

            // Retrieve the reply with a binary attribute type
            retrieveItem(threadId, replyDateTime);

            // clean up by deleting the item
            deleteItem(threadId, replyDateTime);
        } catch (Exception e) {
            System.err.println("Error running the binary attribute type example: " + e);
            e.printStackTrace(System.err);
        }
    }

    public static void createItem(String threadId, String replyDateTime) throws IOException {

        Table table = dynamoDB.getTable(tableName);

        // Craft a long message
        String messageInput = "Long message to be compressed in a lengthy forum reply";

        // Compress the long message
        ByteBuffer compressedMessage = compressString(messageInput.toString());

        table.putItem(new Item().withPrimaryKey("Id", threadId).withString("ReplyDateTime", replyDateTime)
                .withString("Message", "Long message follows").withBinary("ExtendedMessage", compressedMessage)
                .withString("PostedBy", "User A"));
    }

    public static void retrieveItem(String threadId, String replyDateTime) throws IOException {

        Table table = dynamoDB.getTable(tableName);

        GetItemSpec spec = new GetItemSpec().withPrimaryKey("Id", threadId, "ReplyDateTime", replyDateTime)
                .withConsistentRead(true);

        Item item = table.getItem(spec);

        // Uncompress the reply message and print
        String uncompressed = uncompressString(ByteBuffer.wrap(item.getBinary("ExtendedMessage")));

        System.out.println("Reply message:\n" + " Id: " + item.getString("Id") + "\n" + " ReplyDateTime: "
                + item.getString("ReplyDateTime") + "\n" + " PostedBy: " + item.getString("PostedBy") + "\n"
                + " Message: "
                + item.getString("Message") + "\n" + " ExtendedMessage (uncompressed): " + uncompressed + "\n");
    }

    public static void deleteItem(String threadId, String replyDateTime) {

        Table table = dynamoDB.getTable(tableName);
        table.deleteItem("Id", threadId, "ReplyDateTime", replyDateTime);
    }

    private static ByteBuffer compressString(String input) throws IOException {
        // Compress the UTF-8 encoded String into a byte[]
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream os = new GZIPOutputStream(baos);
        os.write(input.getBytes("UTF-8"));
        os.close();
        baos.close();
        byte[] compressedBytes = baos.toByteArray();

        // The following code writes the compressed bytes to a ByteBuffer.
        // A simpler way to do this is by simply calling
        // ByteBuffer.wrap(compressedBytes);
        // However, the longer form below shows the importance of resetting the
        // position of the buffer
        // back to the beginning of the buffer if you are writing bytes directly
        // to it, since the SDK
        // will consider only the bytes after the current position when sending
        // data to DynamoDB.
        // Using the "wrap" method automatically resets the position to zero.
        ByteBuffer buffer = ByteBuffer.allocate(compressedBytes.length);
        buffer.put(compressedBytes, 0, compressedBytes.length);
        buffer.position(0); // Important: reset the position of the ByteBuffer
                            // to the beginning
        return buffer;
    }

    private static String uncompressString(ByteBuffer input) throws IOException {
        byte[] bytes = input.array();
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPInputStream is = new GZIPInputStream(bais);

        int chunkSize = 1024;
        byte[] buffer = new byte[chunkSize];
        int length = 0;
        while ((length = is.read(buffer, 0, chunkSize)) != -1) {
            baos.write(buffer, 0, length);
        }

        String result = new String(baos.toByteArray(), "UTF-8");

        is.close();
        baos.close();
        bais.close();

        return result;
    }
}
```

# Bekerja dengan item: .NET
<a name="LowLevelDotNetItemCRUD"></a>

Anda dapat menggunakan API AWS SDK untuk .NET tingkat rendah untuk melakukan operasi membuat, membaca, memperbarui, dan menghapus (CRUD) pada item dalam tabel. Berikut ini adalah langkah-langkah umum yang Anda ikuti untuk melakukan operasi CRUD data menggunakan API tingkat rendah .NET:

1. Buat instans dari kelas `AmazonDynamoDBClient` (klien).

1. Berikan parameter khusus operasi yang diperlukan dalam objek permintaan yang sesuai.

   Misalnya, gunakan permintaan `PutItemRequest` saat mengunggah item dan gunakan permintaan `GetItemRequest` saat mengambil item yang sudah ada. 

   Anda dapat menggunakan objek permintaan untuk menyediakan parameter wajib dan opsional. 

1. Jalankan metode yang sesuai yang disediakan oleh klien dengan meneruskan objek permintaan yang Anda buat pada langkah sebelumnya. 

   Klien `AmazonDynamoDBClient` menyediakan metode `PutItem`, `GetItem`, `UpdateItem`, dan `DeleteItem` untuk operasi CRUD.

**Topics**
+ [Menempatkan item](#PutItemLowLevelAPIDotNet)
+ [Mendapatkan item](#GetItemLowLevelDotNET)
+ [Memperbarui Item](#UpdateItemLowLevelDotNet)
+ [Penghitung atom](#AtomicCounterLowLevelDotNet)
+ [Menghapus item](#DeleteMidLevelDotNet)
+ [Penulisan batch: Menempatkan dan menghapus beberapa item](#BatchWriteLowLevelDotNet)
+ [Batch get: Mendapatkan beberapa item](#BatchGetLowLevelDotNet)
+ [Contoh: Operasi CRUD menggunakan API tingkat AWS SDK untuk .NET rendah](LowLevelDotNetItemsExample.md)
+ [Contoh: Operasi Batch menggunakan API AWS SDK untuk .NET tingkat rendah](batch-operation-lowlevel-dotnet.md)
+ [Contoh: Menangani atribut tipe biner menggunakan API AWS SDK untuk .NET tingkat rendah](LowLevelDotNetBinaryTypeExample.md)

## Menempatkan item
<a name="PutItemLowLevelAPIDotNet"></a>

Metode `PutItem` mengunggah item ke tabel. Jika item ada, item tersebut akan menggantikan keseluruhan item.

**catatan**  
Alih-alih mengganti seluruh item, jika Anda hanya ingin memperbarui atribut tertentu, Anda dapat menggunakan metode `UpdateItem`. Untuk informasi selengkapnya, lihat [Memperbarui Item](#UpdateItemLowLevelDotNet).

Berikut langkah-langkah untuk mengunggah item menggunakan .NET SDK API tingkat rendah:

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Berikan parameter yang diperlukan dengan membuat instans kelas `PutItemRequest`.

   Untuk menaruh item, Anda harus memberikan nama tabel dan itemnya. 

1. Jalankan metode `PutItem` dengan menyediakan objek `PutItemRequest` yang Anda buat pada langkah sebelumnya.

Contoh \$1C berikut menunjukkan langkah-langkah sebelumnya. Contoh tersebut mengunggah item ke tabel `ProductCatalog`.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new PutItemRequest
{
   TableName = tableName,
   Item = new Dictionary<string, AttributeValue>()
      {
          { "Id", new AttributeValue { N = "201" }},
          { "Title", new AttributeValue { S = "Book 201 Title" }},
          { "ISBN", new AttributeValue { S = "11-11-11-11" }},
          { "Price", new AttributeValue { S = "20.00" }},
          {
            "Authors",
            new AttributeValue
            { SS = new List<string>{"Author1", "Author2"}   }
          }
      }
};
client.PutItem(request);
```

Pada contoh sebelumnya, Anda mengunggah item buku yang memiliki atribut `Id`, `Title`, `ISBN`, dan `Authors`. Perhatikan bahwa `Id` adalah atribut jenis numerik, dan semua atribut lainnya adalah jenis string. Penulis adalah set `String`.

### Menentukan parameter opsional
<a name="PutItemLowLevelAPIDotNetOptions"></a>

Anda juga dapat memberikan parameter opsional menggunakan objek `PutItemRequest` seperti yang ditunjukkan dalam contoh C\$1 berikut. Contoh tersebut menentukan parameter opsional berikut:
+ `ExpressionAttributeNames`, `ExpressionAttributeValues`, dan `ConditionExpression` menentukan bahwa barang tersebut hanya dapat diganti jika barang yang ada memiliki atribut ISBN dengan nilai tertentu.
+ Parameter `ReturnValues` untuk meminta item lama dalam respons.

**Example**  

```
var request = new PutItemRequest
 {
   TableName = tableName,
   Item = new Dictionary<string, AttributeValue>()
               {
                   { "Id", new AttributeValue { N = "104" }},
                   { "Title", new AttributeValue { S = "Book 104  Title" }},
                   { "ISBN", new AttributeValue { S = "444-4444444444" }},
                   { "Authors",
                     new AttributeValue { SS = new List<string>{"Author3"}}}
               },
    // Optional parameters.
    ExpressionAttributeNames = new Dictionary<string,string>()
    {
        {"#I", "ISBN"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":isbn",new AttributeValue {S = "444-4444444444"}}
    },
    ConditionExpression = "#I = :isbn"

};
var response = client.PutItem(request);
```

Untuk informasi selengkapnya, lihat [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html).

## Mendapatkan item
<a name="GetItemLowLevelDotNET"></a>

Metode `GetItem` mengambil item.

**catatan**  
Untuk mengambil beberapa item, Anda dapat menggunakan metode `BatchGetItem`. Untuk informasi selengkapnya, lihat [Batch get: Mendapatkan beberapa item](#BatchGetLowLevelDotNet).

Berikut ini adalah langkah-langkah untuk mengambil item yang ada menggunakan API AWS SDK untuk .NET tingkat rendah.

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Berikan parameter yang diperlukan dengan membuat instans kelas `GetItemRequest`.

   Untuk mendapatkan item, Anda harus memberikan nama tabel dan kunci primer item tersebut. 

1. Jalankan metode `GetItem` dengan menyediakan objek `GetItemRequest` yang Anda buat pada langkah sebelumnya.

Contoh \$1C berikut menunjukkan langkah-langkah sebelumnya. Contoh tersebut mengambil item dari tabel `ProductCatalog`.

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new GetItemRequest
 {
   TableName = tableName,
   Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },
 };
 var response = client.GetItem(request);

// Check the response.
var result = response.GetItemResult;
var attributeMap = result.Item; // Attribute list in the response.
```

### Menentukan parameter opsional
<a name="GetItemLowLevelDotNETOptions"></a>

Anda juga dapat memberikan parameter opsional menggunakan objek `GetItemRequest`, seperti yang ditunjukkan dalam contoh C\$1 berikut. Contoh tersebut menentukan parameter opsional berikut:
+ Parameter `ProjectionExpression` untuk menentukan atribut yang akan diambil.
+ Parameter `ConsistentRead` untuk melakukan bacaan sangat konsisten. Untuk mempelajari selengkapnya tentang konsistensi baca, lihat [DynamoDB membaca konsistensi](HowItWorks.ReadConsistency.md).

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new GetItemRequest
 {
   TableName = tableName,
   Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },
   // Optional parameters.
   ProjectionExpression = "Id, ISBN, Title, Authors",
   ConsistentRead = true
 };

 var response = client.GetItem(request);

// Check the response.
var result = response.GetItemResult;
var attributeMap = result.Item;
```

Untuk informasi selengkapnya, lihat [GetItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html).

## Memperbarui Item
<a name="UpdateItemLowLevelDotNet"></a>

Metode `UpdateItem` memperbarui item yang ada jika ada. Anda dapat menggunakan operasi `UpdateItem` untuk memperbarui nilai atribut yang ada, menambahkan atribut baru, atau menghapus atribut dari koleksi yang ada. Jika item yang memiliki kunci primer yang ditentukan tidak ditemukan, item baru akan ditambahkan.

Operasi `UpdateItem` menggunakan panduan berikut:
+ Jika item tidak ada, `UpdateItem` menambahkan item baru menggunakan kunci primer yang ditentukan dalam input.
+ Jika item ada, `UpdateItem` menerapkan pembaruan sebagai berikut:
  + Menggantikan nilai atribut yang ada dengan nilai dalam pembaruan.
  + Jika atribut yang Anda berikan pada input tidak ada, atribut baru akan ditambahkan ke item tersebut.
  + Jika atribut input adalah null, atribut tersebut akan dihapus, jika ada. 
  + Jika Anda menggunakan `ADD` untuk`Action`, Anda dapat menambahkan nilai ke set yang sudah ada (set string atau angka), atau menambahkan secara matematis (menggunakan angka positif) atau mengurangi (menggunakan angka negatif) dari nilai atribut numerik yang ada.

**catatan**  
Operasi `PutItem` juga dapat melakukan pembaruan. Untuk informasi selengkapnya, lihat [Menempatkan item](#PutItemLowLevelAPIDotNet). Misalnya, jika Anda memanggil `PutItem` untuk mengunggah item dan kunci primer ada, operasi `PutItem` menggantikan seluruh item. Jika terdapat atribut dalam item yang ada yang tidak ditentukan dalam input, operasi `PutItem` akan menghapus atribut tersebut. Namun, `UpdateItem` hanya memperbarui atribut input yang ditentukan. Atribut lain item tersebut yang ada tidak akan berubah. 

Berikut langkah-langkah untuk memperbarui item menggunakan .NET SDK API tingkat rendah:

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Berikan parameter yang diperlukan dengan membuat instans kelas `UpdateItemRequest`.

   Ini adalah objek permintaan tempat Anda menjelaskan semua pembaruan, seperti menambahkan atribut, memperbarui atribut yang ada, atau menghapus atribut. Untuk menghapus atribut yang ada, tentukan nama atribut dengan nilai null. 

1. Jalankan metode `UpdateItem` dengan menyediakan objek `UpdateItemRequest` yang Anda buat pada langkah sebelumnya. 

Contoh kode \$1C berikut mendemonstrasikan langkah sebelumnya. Contoh tersebut memperbarui item buku dalam tabel `ProductCatalog`. Contoh tersebut menambahkan penulis baru ke koleksi `Authors`, dan menghapus atribut `ISBN` yang ada. Contoh tersebut juga mengurangi harga sebanyak satu.



```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new UpdateItemRequest
{
    TableName = tableName,
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },
    ExpressionAttributeNames = new Dictionary<string,string>()
    {
        {"#A", "Authors"},
        {"#P", "Price"},
        {"#NA", "NewAttribute"},
        {"#I", "ISBN"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":auth",new AttributeValue { SS = {"Author YY","Author ZZ"}}},
        {":p",new AttributeValue {N = "1"}},
        {":newattr",new AttributeValue {S = "someValue"}},
    },

    // This expression does the following:
    // 1) Adds two new authors to the list
    // 2) Reduces the price
    // 3) Adds a new attribute to the item
    // 4) Removes the ISBN attribute from the item
    UpdateExpression = "ADD #A :auth SET #P = #P - :p, #NA = :newattr REMOVE #I"
};
var response = client.UpdateItem(request);
```

### Menentukan parameter opsional
<a name="UpdateItemLowLevelDotNETOptions"></a>

Anda juga dapat memberikan parameter opsional menggunakan objek `UpdateItemRequest`, seperti yang ditunjukkan dalam contoh C\$1 berikut. Contoh tersebut menentukan parameter opsional berikut:
+ `ExpressionAttributeValues` dan `ConditionExpression` untuk menentukan bahwa harga dapat diperbarui hanya jika harga yang ada adalah 20,00.
+ Parameter `ReturnValues` untuk meminta item yang diperbarui dalam respons. 

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new UpdateItemRequest
{
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },

    // Update price only if the current price is 20.00.
    ExpressionAttributeNames = new Dictionary<string,string>()
    {
        {"#P", "Price"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":newprice",new AttributeValue {N = "22"}},
        {":currprice",new AttributeValue {N = "20"}}
    },
    UpdateExpression = "SET #P = :newprice",
    ConditionExpression = "#P = :currprice",
    TableName = tableName,
    ReturnValues = "ALL_NEW" // Return all the attributes of the updated item.
};

var response = client.UpdateItem(request);
```

Untuk informasi selengkapnya, lihat [UpdateItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html). 

## Penghitung atom
<a name="AtomicCounterLowLevelDotNet"></a>

Anda dapat menggunakan `updateItem` untuk mengimplementasi penghitung atom, di mana Anda menambahkan atau mengurangi nilai atribut yang ada tanpa mengganggu permintaan tulis lainnya. Untuk memperbarui penghitung atom, gunakan `updateItem` dengan atribut jenis `Number` dalam parameter `UpdateExpression`, dan `ADD` sebagai `Action`.

Contoh berikut menunjukkan hal ini, menambahkan satu atribut `Quantity`.

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new UpdateItemRequest
{
    Key = new Dictionary<string, AttributeValue>() { { "Id", new AttributeValue { N = "121" } } },
    ExpressionAttributeNames = new Dictionary<string, string>()
    {
        {"#Q", "Quantity"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":incr",new AttributeValue {N = "1"}}
    },
    UpdateExpression = "SET #Q = #Q + :incr",
    TableName = tableName
};

var response = client.UpdateItem(request);
```

## Menghapus item
<a name="DeleteMidLevelDotNet"></a>

Metode `DeleteItem` menghapus item dari tabel. 

Berikut ini adalah langkah-langkah untuk menghapus item menggunakan .NET SDK API tingkat rendah. 

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Berikan parameter yang diperlukan dengan membuat instans kelas `DeleteItemRequest`.

    Untuk menghapus item, diperlukan nama tabel dan kunci primer item. 

1. Jalankan metode `DeleteItem` dengan menyediakan objek `DeleteItemRequest` yang Anda buat pada langkah sebelumnya. 

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new DeleteItemRequest
{
    TableName = tableName,
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "201" } } },
};

var response = client.DeleteItem(request);
```

### Menentukan parameter opsional
<a name="DeleteItemLowLevelDotNETOptions"></a>

Anda juga dapat memberikan parameter opsional menggunakan objek `DeleteItemRequest` seperti yang ditunjukkan dalam contoh kode C\$1 berikut. Contoh tersebut menentukan parameter opsional berikut:
+ `ExpressionAttributeValues`dan `ConditionExpression` untuk menentukan bahwa item buku dapat dihapus hanya jika tidak lagi dalam publikasi (nilai InPublication atribut salah). 
+ Parameter `ReturnValues` untuk meminta item yang dihapus dalam respons.

**Example**  

```
var request = new DeleteItemRequest
{
    TableName = tableName,
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "201" } } },

    // Optional parameters.
    ReturnValues = "ALL_OLD",
    ExpressionAttributeNames = new Dictionary<string, string>()
    {
        {"#IP", "InPublication"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":inpub",new AttributeValue {BOOL = false}}
    },
    ConditionExpression = "#IP = :inpub"
};

var response = client.DeleteItem(request);
```

Untuk informasi selengkapnya, lihat [DeleteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DeleteItem.html).

## Penulisan batch: Menempatkan dan menghapus beberapa item
<a name="BatchWriteLowLevelDotNet"></a>

*Penulisan batch* merujuk pada penempatan dan penghapusan beberapa item dalam satu batch. Metode `BatchWriteItem` memungkinkan Anda untuk memasukkan dan menghapus beberapa item dari satu atau lebih tabel dalam satu panggilan. Berikut ini adalah langkah-langkah untuk mengambil beberapa item menggunakan .NET SDK API tingkat rendah.

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Jelaskan semua operasi tempatkan dan hapus dengan membuat instans dari kelas `BatchWriteItemRequest`.

1. Jalankan metode `BatchWriteItem` dengan menyediakan objek `BatchWriteItemRequest` yang Anda buat pada langkah sebelumnya.

1. Proses responsnya. Anda harus memeriksa apakah ada item permintaan yang belum diproses yang dikembalikan sebagai respons. Hal ini dapat terjadi jika Anda mencapai kuota throughput yang disediakan atau kesalahan sementara lainnya. Selain itu, DynamoDB membatasi ukuran permintaan dan jumlah operasi yang dapat Anda tentukan dalam permintaan. Jika Anda melebihi batas ini, DynamoDB menolak permintaan tersebut. Untuk informasi selengkapnya, lihat [BatchWriteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html). 

Contoh kode \$1C berikut mendemonstrasikan langkah sebelumnya. Contoh ini membuat `BatchWriteItemRequest` untuk melakukan operasi tulis berikut:
+ Tempatkan satu item dalam tabel `Forum`.
+ Tempatkan dan hapus satu item dari tabel `Thread`.

Kode menjalankan `BatchWriteItem` untuk melakukan operasi batch.

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();

string table1Name = "Forum";
string table2Name = "Thread";

var request = new BatchWriteItemRequest
 {
   RequestItems = new Dictionary<string, List<WriteRequest>>
    {
      {
        table1Name, new List<WriteRequest>
        {
          new WriteRequest
          {
             PutRequest = new PutRequest
             {
                Item = new Dictionary<string,AttributeValue>
                {
                  { "Name", new AttributeValue { S = "Amazon S3 forum" } },
                  { "Threads", new AttributeValue { N = "0" }}
                }
             }
          }
        }
      } ,
      {
        table2Name, new List<WriteRequest>
        {
          new WriteRequest
          {
            PutRequest = new PutRequest
            {
               Item = new Dictionary<string,AttributeValue>
               {
                 { "ForumName", new AttributeValue { S = "Amazon S3 forum" } },
                 { "Subject", new AttributeValue { S = "My sample question" } },
                 { "Message", new AttributeValue { S = "Message Text." } },
                 { "KeywordTags", new AttributeValue { SS = new List<string> { "Amazon S3", "Bucket" }  } }
               }
            }
          },
          new WriteRequest
          {
             DeleteRequest = new DeleteRequest
             {
                Key = new Dictionary<string,AttributeValue>()
                {
                   { "ForumName", new AttributeValue { S = "Some forum name" } },
                   { "Subject", new AttributeValue { S = "Some subject" } }
                }
             }
          }
        }
      }
    }
 };
response = client.BatchWriteItem(request);
```

Untuk contoh pekerjaan, lihat [Contoh: Operasi Batch menggunakan API AWS SDK untuk .NET tingkat rendah](batch-operation-lowlevel-dotnet.md). 

## Batch get: Mendapatkan beberapa item
<a name="BatchGetLowLevelDotNet"></a>

Metode `BatchGetItem` memungkinkan Anda mengambil beberapa item dari satu atau lebih tabel. 

**catatan**  
Untuk mengambil satu item, Anda dapat menggunakan metode `GetItem`. 

Berikut ini adalah langkah-langkah untuk mengambil beberapa item menggunakan API AWS SDK untuk .NET tingkat rendah.

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Berikan parameter yang diperlukan dengan membuat instans kelas `BatchGetItemRequest`.

   Untuk mengambil beberapa item, nama tabel dan daftar nilai kunci primer diperlukan. 

1. Jalankan metode `BatchGetItem` dengan menyediakan objek `BatchGetItemRequest` yang Anda buat pada langkah sebelumnya.

1. Proses responsnya. Anda harus memeriksa apakah ada kunci yang belum diproses, yang dapat terjadi jika Anda mencapai kuota throughput yang disediakan atau kesalahan sementara lainnya.

Contoh kode \$1C berikut mendemonstrasikan langkah sebelumnya. Contoh tersebut mengambil item dari dua tabel, `Forum` dan `Thread`. Permintaan menentukan dua item dalam `Forum` dan tiga item dalam tabel `Thread`. Respons tersebut mencakup item dari kedua tabel. Kode tersebut menunjukkan bagaimana Anda dapat memproses respons.



```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();

string table1Name = "Forum";
string table2Name = "Thread";

var request = new BatchGetItemRequest
{
  RequestItems = new Dictionary<string, KeysAndAttributes>()
  {
    { table1Name,
      new KeysAndAttributes
      {
        Keys = new List<Dictionary<string, AttributeValue>>()
        {
          new Dictionary<string, AttributeValue>()
          {
            { "Name", new AttributeValue { S = "DynamoDB" } }
          },
          new Dictionary<string, AttributeValue>()
          {
            { "Name", new AttributeValue { S = "Amazon S3" } }
          }
        }
      }
    },
    {
      table2Name,
      new KeysAndAttributes
      {
        Keys = new List<Dictionary<string, AttributeValue>>()
        {
          new Dictionary<string, AttributeValue>()
          {
            { "ForumName", new AttributeValue { S = "DynamoDB" } },
            { "Subject", new AttributeValue { S = "DynamoDB Thread 1" } }
          },
          new Dictionary<string, AttributeValue>()
          {
            { "ForumName", new AttributeValue { S = "DynamoDB" } },
            { "Subject", new AttributeValue { S = "DynamoDB Thread 2" } }
          },
          new Dictionary<string, AttributeValue>()
          {
            { "ForumName", new AttributeValue { S = "Amazon S3" } },
            { "Subject", new AttributeValue { S = "Amazon S3 Thread 1" } }
          }
        }
      }
    }
  }
};

var response = client.BatchGetItem(request);

// Check the response.
var result = response.BatchGetItemResult;
var responses = result.Responses; // The attribute list in the response.

var table1Results = responses[table1Name];
Console.WriteLine("Items in table {0}" + table1Name);
foreach (var item1 in table1Results.Items)
{
  PrintItem(item1);
}

var table2Results = responses[table2Name];
Console.WriteLine("Items in table {1}" + table2Name);
foreach (var item2 in table2Results.Items)
{
  PrintItem(item2);
}
// Any unprocessed keys? could happen if you exceed ProvisionedThroughput or some other error.
Dictionary<string, KeysAndAttributes> unprocessedKeys = result.UnprocessedKeys;
foreach (KeyValuePair<string, KeysAndAttributes> pair in unprocessedKeys)
{
    Console.WriteLine(pair.Key, pair.Value);
}
```



### Menentukan parameter opsional
<a name="BatchGetItemLowLevelDotNETOptions"></a>

Anda juga dapat memberikan parameter opsional menggunakan objek `BatchGetItemRequest` seperti yang ditunjukkan dalam contoh kode C\$1 berikut. Contoh tersebut mengambil dua item dari tabel `Forum`. Contoh tersebut menentukan parameter opsional berikut:
+  Parameter `ProjectionExpression` untuk menentukan atribut yang akan diambil.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();

string table1Name = "Forum";

var request = new BatchGetItemRequest
{
  RequestItems = new Dictionary<string, KeysAndAttributes>()
  {
    { table1Name,
      new KeysAndAttributes
      {
        Keys = new List<Dictionary<string, AttributeValue>>()
        {
          new Dictionary<string, AttributeValue>()
          {
            { "Name", new AttributeValue { S = "DynamoDB" } }
          },
          new Dictionary<string, AttributeValue>()
          {
            { "Name", new AttributeValue { S = "Amazon S3" } }
          }
        }
      },
      // Optional - name of an attribute to retrieve.
      ProjectionExpression = "Title"
    }
  }
};

var response = client.BatchGetItem(request);
```

Untuk informasi selengkapnya, lihat [BatchGetItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html). 

# Contoh: Operasi CRUD menggunakan API tingkat AWS SDK untuk .NET rendah
<a name="LowLevelDotNetItemsExample"></a>

Contoh kode C\$1 berikut menunjukkan operasi CRUD pada item Amazon DynamoDB. Contoh tersebut menambahkan item ke tabel `ProductCatalog`, mengambilnya, melakukan berbagai pembaruan, dan akhirnya menghapus item. Jika Anda belum membuat tabel ini, Anda juga dapat membuatnya secara terprogram. Untuk informasi selengkapnya, lihat [Membuat tabel contoh dan mengunggah data menggunakan AWS SDK untuk .NET](AppendixSampleDataCodeDotNET.md).

Untuk step-by-step instruksi untuk menguji sampel berikut, lihat[Contoh kode .NET](CodeSamples.DotNet.md). 

**Example**  

```
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;
using Amazon.SecurityToken;

namespace com.amazonaws.codesamples
{
    class LowLevelItemCRUDExample
    {
        private static string tableName = "ProductCatalog";
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            try
            {
                CreateItem();
                RetrieveItem();

                // Perform various updates.
                UpdateMultipleAttributes();
                UpdateExistingAttributeConditionally();

                // Delete item.
                DeleteItem();
                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
        }

        private static void CreateItem()
        {
            var request = new PutItemRequest
            {
                TableName = tableName,
                Item = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  }},
                { "Title", new AttributeValue {
                      S = "Book 201 Title"
                  }},
                { "ISBN", new AttributeValue {
                      S = "11-11-11-11"
                  }},
                { "Authors", new AttributeValue {
                      SS = new List<string>{"Author1", "Author2" }
                  }},
                { "Price", new AttributeValue {
                      N = "20.00"
                  }},
                { "Dimensions", new AttributeValue {
                      S = "8.5x11.0x.75"
                  }},
                { "InPublication", new AttributeValue {
                      BOOL = false
                  } }
            }
            };
            client.PutItem(request);
        }

        private static void RetrieveItem()
        {
            var request = new GetItemRequest
            {
                TableName = tableName,
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  } }
            },
                ProjectionExpression = "Id, ISBN, Title, Authors",
                ConsistentRead = true
            };
            var response = client.GetItem(request);

            // Check the response.
            var attributeList = response.Item; // attribute list in the response.
            Console.WriteLine("\nPrinting item after retrieving it ............");
            PrintItem(attributeList);
        }

        private static void UpdateMultipleAttributes()
        {
            var request = new UpdateItemRequest
            {
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  } }
            },
                // Perform the following updates:
                // 1) Add two new authors to the list
                // 1) Set a new attribute
                // 2) Remove the ISBN attribute
                ExpressionAttributeNames = new Dictionary<string, string>()
            {
                {"#A","Authors"},
                {"#NA","NewAttribute"},
                {"#I","ISBN"}
            },
                ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
            {
                {":auth",new AttributeValue {
                     SS = {"Author YY", "Author ZZ"}
                 }},
                {":new",new AttributeValue {
                     S = "New Value"
                 }}
            },

                UpdateExpression = "ADD #A :auth SET #NA = :new REMOVE #I",

                TableName = tableName,
                ReturnValues = "ALL_NEW" // Give me all attributes of the updated item.
            };
            var response = client.UpdateItem(request);

            // Check the response.
            var attributeList = response.Attributes; // attribute list in the response.
                                                     // print attributeList.
            Console.WriteLine("\nPrinting item after multiple attribute update ............");
            PrintItem(attributeList);
        }

        private static void UpdateExistingAttributeConditionally()
        {
            var request = new UpdateItemRequest
            {
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  } }
            },
                ExpressionAttributeNames = new Dictionary<string, string>()
            {
                {"#P", "Price"}
            },
                ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
            {
                {":newprice",new AttributeValue {
                     N = "22.00"
                 }},
                {":currprice",new AttributeValue {
                     N = "20.00"
                 }}
            },
                // This updates price only if current price is 20.00.
                UpdateExpression = "SET #P = :newprice",
                ConditionExpression = "#P = :currprice",

                TableName = tableName,
                ReturnValues = "ALL_NEW" // Give me all attributes of the updated item.
            };
            var response = client.UpdateItem(request);

            // Check the response.
            var attributeList = response.Attributes; // attribute list in the response.
            Console.WriteLine("\nPrinting item after updating price value conditionally ............");
            PrintItem(attributeList);
        }

        private static void DeleteItem()
        {
            var request = new DeleteItemRequest
            {
                TableName = tableName,
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  } }
            },

                // Return the entire item as it appeared before the update.
                ReturnValues = "ALL_OLD",
                ExpressionAttributeNames = new Dictionary<string, string>()
            {
                {"#IP", "InPublication"}
            },
                ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
            {
                {":inpub",new AttributeValue {
                     BOOL = false
                 }}
            },
                ConditionExpression = "#IP = :inpub"
            };

            var response = client.DeleteItem(request);

            // Check the response.
            var attributeList = response.Attributes; // Attribute list in the response.
                                                     // Print item.
            Console.WriteLine("\nPrinting item that was just deleted ............");
            PrintItem(attributeList);
        }

        private static void PrintItem(Dictionary<string, AttributeValue> attributeList)
        {
            foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
            {
                string attributeName = kvp.Key;
                AttributeValue value = kvp.Value;

                Console.WriteLine(
                    attributeName + " " +
                    (value.S == null ? "" : "S=[" + value.S + "]") +
                    (value.N == null ? "" : "N=[" + value.N + "]") +
                    (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
                    (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]")
                    );
            }
            Console.WriteLine("************************************************");
        }
    }
}
```

# Contoh: Operasi Batch menggunakan API AWS SDK untuk .NET tingkat rendah
<a name="batch-operation-lowlevel-dotnet"></a>

**Topics**
+ [Contoh: Operasi penulisan Batch menggunakan API AWS SDK untuk .NET tingkat rendah](#batch-write-low-level-dotnet)
+ [Contoh: Batch get operation menggunakan API AWS SDK untuk .NET tingkat rendah](#LowLevelDotNetBatchGet)

Bagian ini memberikan contoh operasi batch, *batch write* dan *batch get*, yang mendukung Amazon DynamoDB.

## Contoh: Operasi penulisan Batch menggunakan API AWS SDK untuk .NET tingkat rendah
<a name="batch-write-low-level-dotnet"></a>

Contoh kode C\$1 berikut menggunakan metode `BatchWriteItem` untuk melakukan operasi put dan delete berikut:
+ Tempatkan satu item dalam tabel `Forum`.
+ Tempatkan satu item dan hapus satu item dari tabel `Thread`. 

Anda dapat menentukan sejumlah permintaan put dan delete terhadap satu atau beberapa tabel saat membuat permintaan batch write Anda. Namun, `BatchWriteItem` DynamoDB membatasi ukuran permintaan penulisan batch dan jumlah operasi put dan delete dalam satu operasi penulisan batch. Untuk informasi selengkapnya, lihat [BatchWriteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html). Jika permintaan Anda melebihi batas ini, permintaan Anda ditolak. Jika tabel Anda tidak memiliki cukup throughput yang disediakan untuk melayani permintaan ini, item permintaan yang belum diproses akan dikembalikan sebagai respons. 

Contoh berikut memeriksa respons untuk melihat apakah ada item permintaan yang belum diproses. Jika ya, contoh tersebut akan mengulang kembali dan mengirim ulang permintaan `BatchWriteItem` dengan item yang belum diproses dalam permintaan tersebut. Anda juga dapat membuat tabel sampel ini dan mengunggah data sampel secara terprogram. Untuk informasi selengkapnya, lihat [Membuat tabel contoh dan mengunggah data menggunakan AWS SDK untuk .NET](AppendixSampleDataCodeDotNET.md).

Untuk step-by-step instruksi untuk menguji sampel berikut, lihat[Contoh kode .NET](CodeSamples.DotNet.md). 

**Example**  

```
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;

namespace com.amazonaws.codesamples
{
    class LowLevelBatchWrite
    {
        private static string table1Name = "Forum";
        private static string table2Name = "Thread";
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            try
            {
                TestBatchWrite();
            }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }

            Console.WriteLine("To continue, press Enter");
            Console.ReadLine();
        }

        private static void TestBatchWrite()
        {
            var request = new BatchWriteItemRequest
            {
                ReturnConsumedCapacity = "TOTAL",
                RequestItems = new Dictionary<string, List<WriteRequest>>
            {
                {
                    table1Name, new List<WriteRequest>
                    {
                        new WriteRequest
                        {
                            PutRequest = new PutRequest
                            {
                                Item = new Dictionary<string, AttributeValue>
                                {
                                    { "Name", new AttributeValue {
                                          S = "S3 forum"
                                      } },
                                    { "Threads", new AttributeValue {
                                          N = "0"
                                      }}
                                }
                            }
                        }
                    }
                },
                {
                    table2Name, new List<WriteRequest>
                    {
                        new WriteRequest
                        {
                            PutRequest = new PutRequest
                            {
                                Item = new Dictionary<string, AttributeValue>
                                {
                                    { "ForumName", new AttributeValue {
                                          S = "S3 forum"
                                      } },
                                    { "Subject", new AttributeValue {
                                          S = "My sample question"
                                      } },
                                    { "Message", new AttributeValue {
                                          S = "Message Text."
                                      } },
                                    { "KeywordTags", new AttributeValue {
                                          SS = new List<string> { "S3", "Bucket" }
                                      } }
                                }
                            }
                        },
                        new WriteRequest
                        {
                            // For the operation to delete an item, if you provide a primary key value
                            // that does not exist in the table, there is no error, it is just a no-op.
                            DeleteRequest = new DeleteRequest
                            {
                                Key = new Dictionary<string, AttributeValue>()
                                {
                                    { "ForumName",  new AttributeValue {
                                          S = "Some partition key value"
                                      } },
                                    { "Subject", new AttributeValue {
                                          S = "Some sort key value"
                                      } }
                                }
                            }
                        }
                    }
                }
            }
            };

            CallBatchWriteTillCompletion(request);
        }

        private static void CallBatchWriteTillCompletion(BatchWriteItemRequest request)
        {
            BatchWriteItemResponse response;

            int callCount = 0;
            do
            {
                Console.WriteLine("Making request");
                response = client.BatchWriteItem(request);
                callCount++;

                // Check the response.

                var tableConsumedCapacities = response.ConsumedCapacity;
                var unprocessed = response.UnprocessedItems;

                Console.WriteLine("Per-table consumed capacity");
                foreach (var tableConsumedCapacity in tableConsumedCapacities)
                {
                    Console.WriteLine("{0} - {1}", tableConsumedCapacity.TableName, tableConsumedCapacity.CapacityUnits);
                }

                Console.WriteLine("Unprocessed");
                foreach (var unp in unprocessed)
                {
                    Console.WriteLine("{0} - {1}", unp.Key, unp.Value.Count);
                }
                Console.WriteLine();

                // For the next iteration, the request will have unprocessed items.
                request.RequestItems = unprocessed;
            } while (response.UnprocessedItems.Count > 0);

            Console.WriteLine("Total # of batch write API calls made: {0}", callCount);
        }
    }
}
```

## Contoh: Batch get operation menggunakan API AWS SDK untuk .NET tingkat rendah
<a name="LowLevelDotNetBatchGet"></a>

Contoh kode C\$1 berikut menggunakan metode `BatchGetItem` untuk mengambil beberapa item dari tabel `Forum` dan `Thread` dalam Amazon DynamoDB. `BatchGetItemRequest` menentukan nama tabel dan daftar kunci primer untuk setiap tabel. Contoh tersebut memproses respons dengan mencetak item yang diambil. 

Untuk step-by-step instruksi untuk menguji sampel berikut, lihat[Contoh kode .NET](CodeSamples.DotNet.md). 

**Example**  

```
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;

namespace com.amazonaws.codesamples
{
    class LowLevelBatchGet
    {
        private static string table1Name = "Forum";
        private static string table2Name = "Thread";
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            try
            {
                RetrieveMultipleItemsBatchGet();

                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }
        }

        private static void RetrieveMultipleItemsBatchGet()
        {
            var request = new BatchGetItemRequest
            {
                RequestItems = new Dictionary<string, KeysAndAttributes>()
            {
                { table1Name,
                  new KeysAndAttributes
                  {
                      Keys = new List<Dictionary<string, AttributeValue> >()
                      {
                          new Dictionary<string, AttributeValue>()
                          {
                              { "Name", new AttributeValue {
                            S = "Amazon DynamoDB"
                        } }
                          },
                          new Dictionary<string, AttributeValue>()
                          {
                              { "Name", new AttributeValue {
                            S = "Amazon S3"
                        } }
                          }
                      }
                  }},
                {
                    table2Name,
                    new KeysAndAttributes
                    {
                        Keys = new List<Dictionary<string, AttributeValue> >()
                        {
                            new Dictionary<string, AttributeValue>()
                            {
                                { "ForumName", new AttributeValue {
                                      S = "Amazon DynamoDB"
                                  } },
                                { "Subject", new AttributeValue {
                                      S = "DynamoDB Thread 1"
                                  } }
                            },
                            new Dictionary<string, AttributeValue>()
                            {
                                { "ForumName", new AttributeValue {
                                      S = "Amazon DynamoDB"
                                  } },
                                { "Subject", new AttributeValue {
                                      S = "DynamoDB Thread 2"
                                  } }
                            },
                            new Dictionary<string, AttributeValue>()
                            {
                                { "ForumName", new AttributeValue {
                                      S = "Amazon S3"
                                  } },
                                { "Subject", new AttributeValue {
                                      S = "S3 Thread 1"
                                  } }
                            }
                        }
                    }
                }
            }
            };

            BatchGetItemResponse response;
            do
            {
                Console.WriteLine("Making request");
                response = client.BatchGetItem(request);

                // Check the response.
                var responses = response.Responses; // Attribute list in the response.

                foreach (var tableResponse in responses)
                {
                    var tableResults = tableResponse.Value;
                    Console.WriteLine("Items retrieved from table {0}", tableResponse.Key);
                    foreach (var item1 in tableResults)
                    {
                        PrintItem(item1);
                    }
                }

                // Any unprocessed keys? could happen if you exceed ProvisionedThroughput or some other error.
                Dictionary<string, KeysAndAttributes> unprocessedKeys = response.UnprocessedKeys;
                foreach (var unprocessedTableKeys in unprocessedKeys)
                {
                    // Print table name.
                    Console.WriteLine(unprocessedTableKeys.Key);
                    // Print unprocessed primary keys.
                    foreach (var key in unprocessedTableKeys.Value.Keys)
                    {
                        PrintItem(key);
                    }
                }

                request.RequestItems = unprocessedKeys;
            } while (response.UnprocessedKeys.Count > 0);
        }

        private static void PrintItem(Dictionary<string, AttributeValue> attributeList)
        {
            foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
            {
                string attributeName = kvp.Key;
                AttributeValue value = kvp.Value;

                Console.WriteLine(
                    attributeName + " " +
                    (value.S == null ? "" : "S=[" + value.S + "]") +
                    (value.N == null ? "" : "N=[" + value.N + "]") +
                    (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
                    (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]")
                    );
            }
            Console.WriteLine("************************************************");
        }
    }
}
```

# Contoh: Menangani atribut tipe biner menggunakan API AWS SDK untuk .NET tingkat rendah
<a name="LowLevelDotNetBinaryTypeExample"></a>

Contoh kode C\$1 berikut menggambarkan penanganan atribut jenis biner. Contoh tersebut menambahkan item ke tabel `Reply`. Item termasuk atribut jenis biner (`ExtendedMessage`) yang menyimpan data terkompresi. Contoh tersebut kemudian mengambil item dan mencetak semua nilai atribut. Sebagai ilustrasi, contoh menggunakan kelas `GZipStream` untuk mengompresi aliran sampel dan menetapkannya ke atribut `ExtendedMessage`, serta mendekompresinya saat mencetak nilai atribut. 

Untuk step-by-step instruksi untuk menguji contoh berikut, lihat[Contoh kode .NET](CodeSamples.DotNet.md). 

**Example**  

```
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;

namespace com.amazonaws.codesamples
{
    class LowLevelItemBinaryExample
    {
        private static string tableName = "Reply";
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            // Reply table primary key.
            string replyIdPartitionKey = "Amazon DynamoDB#DynamoDB Thread 1";
            string replyDateTimeSortKey = Convert.ToString(DateTime.UtcNow);

            try
            {
                CreateItem(replyIdPartitionKey, replyDateTimeSortKey);
                RetrieveItem(replyIdPartitionKey, replyDateTimeSortKey);
                // Delete item.
                DeleteItem(replyIdPartitionKey, replyDateTimeSortKey);
                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (AmazonDynamoDBException e) { Console.WriteLine(e.Message); }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }
        }

        private static void CreateItem(string partitionKey, string sortKey)
        {
            MemoryStream compressedMessage = ToGzipMemoryStream("Some long extended message to compress.");
            var request = new PutItemRequest
            {
                TableName = tableName,
                Item = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      S = partitionKey
                  }},
                { "ReplyDateTime", new AttributeValue {
                      S = sortKey
                  }},
                { "Subject", new AttributeValue {
                      S = "Binary type "
                  }},
                { "Message", new AttributeValue {
                      S = "Some message about the binary type"
                  }},
                { "ExtendedMessage", new AttributeValue {
                      B = compressedMessage
                  }}
            }
            };
            client.PutItem(request);
        }

        private static void RetrieveItem(string partitionKey, string sortKey)
        {
            var request = new GetItemRequest
            {
                TableName = tableName,
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      S = partitionKey
                  } },
                { "ReplyDateTime", new AttributeValue {
                      S = sortKey
                  } }
            },
                ConsistentRead = true
            };
            var response = client.GetItem(request);

            // Check the response.
            var attributeList = response.Item; // attribute list in the response.
            Console.WriteLine("\nPrinting item after retrieving it ............");

            PrintItem(attributeList);
        }

        private static void DeleteItem(string partitionKey, string sortKey)
        {
            var request = new DeleteItemRequest
            {
                TableName = tableName,
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      S = partitionKey
                  } },
                { "ReplyDateTime", new AttributeValue {
                      S = sortKey
                  } }
            }
            };
            var response = client.DeleteItem(request);
        }

        private static void PrintItem(Dictionary<string, AttributeValue> attributeList)
        {
            foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
            {
                string attributeName = kvp.Key;
                AttributeValue value = kvp.Value;

                Console.WriteLine(
                    attributeName + " " +
                    (value.S == null ? "" : "S=[" + value.S + "]") +
                    (value.N == null ? "" : "N=[" + value.N + "]") +
                    (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
                    (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]") +
                    (value.B == null ? "" : "B=[" + FromGzipMemoryStream(value.B) + "]")
                    );
            }
            Console.WriteLine("************************************************");
        }

        private static MemoryStream ToGzipMemoryStream(string value)
        {
            MemoryStream output = new MemoryStream();
            using (GZipStream zipStream = new GZipStream(output, CompressionMode.Compress, true))
            using (StreamWriter writer = new StreamWriter(zipStream))
            {
                writer.Write(value);
            }
            return output;
        }

        private static string FromGzipMemoryStream(MemoryStream stream)
        {
            using (GZipStream zipStream = new GZipStream(stream, CompressionMode.Decompress))
            using (StreamReader reader = new StreamReader(zipStream))
            {
                return reader.ReadToEnd();
            }
        }
    }
}
```

# Meningkatkan akses data dengan indeks sekunder di DynamoDB
<a name="SecondaryIndexes"></a>

Amazon DynamoDB menyediakan akses cepat ke item-item dalam sebuah tabel dengan menentukan nilai-nilai kunci primer. Namun, banyak aplikasi mungkin mendapat manfaat dari tersedianya satu atau lebih kunci sekunder (atau alternatif), untuk memungkinkan akses efisien ke data dengan atribut selain kunci primer. Untuk mengatasi hal ini, Anda dapat membuat satu atau lebih indeks sekunder pada tabel dan mengeluarkan permintaan `Query` atau `Scan` terhadap indeks ini.

*Indeks sekunder* adalah struktur data yang berisi subset atribut dari tabel, bersama dengan kunci alternatif untuk mendukung operasi `Query`. Anda dapat mengambil data dari indeks menggunakan sebuah `Query`, dengan cara yang sama seperti saat Anda menggunakan `Query` dengan tabel. Sebuah tabel dapat memiliki beberapa indeks sekunder, yang memberikan aplikasi Anda akses ke banyak pola kueri yang berbeda.

**catatan**  
Anda juga dapat melakukan `Scan` pada indeks, dengan cara yang sama seperti Anda melakukan `Scan` pada tabel.   
Akses lintas akun untuk operasi pemindaian indeks sekunder saat ini tidak didukung dengan kebijakan berbasis [sumber daya](access-control-resource-based.md).

Setiap indeks sekunder dikaitkan dengan tepat satu tabel, dari mana indeks memperoleh datanya. Ini disebut *tabel dasar* untuk indeks. Saat Anda membuat indeks, Anda menentukan kunci alternatif untuk indeks tersebut (kunci partisi dan kunci urutan). Anda juga menentukan atribut yang ingin Anda *proyeksikan*, atau salin, dari tabel dasar ke dalam indeks. DynamoDB menyalin atribut ini ke dalam indeks, bersama dengan atribut kunci primer dari tabel dasar. Anda kemudian dapat mengkueri atau memindai indeks sama seperti Anda mengkueri atau memindai tabel. 

Setiap indeks sekunder dikelola secara otomatis oleh DynamoDB. Saat Anda menambahkan, mengubah, atau menghapus item di tabel dasar, indeks apa pun di tabel tersebut juga diperbarui untuk mencerminkan perubahan ini.

DynamoDB mendukung dua jenis indeks sekunder:
+ **[Indeks sekunder global](GSI.html) — **Indeks dengan kunci partisi dan kunci urutan yang mungkin berbeda dari yang ada di tabel dasar. Indeks sekunder global dianggap "global" karena kueri pada indeks dapat menjangkau semua data di tabel dasar, di semua partisi. Indeks sekunder global disimpan dalam ruang partisinya sendiri jauh dari tabel dasar dan diskalakan secara terpisah dari tabel dasar.
+ **[Indeks sekunder lokal](LSI.html) – **Indeks yang memiliki kunci partisi yang sama dengan tabel, namun kunci urutan berbeda. Indeks sekunder lokal bersifat "lokal" dalam arti bahwa setiap partisi indeks sekunder lokal dicakup ke partisi tabel dasar yang memiliki nilai kunci partisi yang sama.

Untuk perbandingan indeks sekunder global dan indeks sekunder lokal, lihat video ini.

[![AWS Videos](http://img.youtube.com/vi/https://www.youtube.com/embed/BkEu7zBWge8/0.jpg)](http://www.youtube.com/watch?v=https://www.youtube.com/embed/BkEu7zBWge8)


**Topics**
+ [Menggunakan Indeks Sekunder Global di DynamoDB](GSI.md)
+ [Indeks sekunder lokal](LSI.md)

Anda harus mempertimbangkan persyaratan aplikasi Anda saat menentukan jenis indeks yang akan digunakan. Tabel berikut menunjukkan perbedaan utama antara indeks sekunder global dan indeks sekunder lokal.


****  

| Karakteristik | Indeks sekunder global | Indeks sekunder lokal | 
| --- | --- | --- | 
| Skema Kunci | Kunci primer indeks sekunder global dapat berupa sederhana (kunci partisi) atau gabungan (kunci partisi dan kunci urutan). | Kunci primer dari indeks sekunder lokal harus gabungan (kunci partisi dan kunci urutan). | 
| Atribut Kunci | Kunci partisi indeks dan kunci urutan (jika ada) dapat berupa atribut tabel dasar apa pun berupa jenis string, angka, atau biner. | Kunci partisi indeks adalah atribut yang sama dengan kunci partisi dari tabel dasar. Kunci urutan dapat berupa atribut tabel dasar apa pun dari jenis string, angka, atau biner. | 
| Pembatasan Ukuran Per Nilai Kunci Partisi | Tidak ada batasan ukuran untuk indeks sekunder global. | Untuk setiap nilai kunci partisi, ukuran total semua item yang diindeks harus 10 GB atau kurang. | 
| Operasi Indeks Online | Indeks sekunder global dapat dibuat pada saat yang sama saat Anda membuat tabel. Anda juga dapat menambahkan indeks sekunder global baru ke tabel yang ada, atau menghapus indeks sekunder global yang ada. Untuk informasi selengkapnya, lihat [Mengelola Indeks Sekunder Global di DynamoDB](GSI.OnlineOps.md).  | Indeks sekunder lokal dibuat pada saat yang sama saat Anda membuat tabel. Anda tidak dapat menambahkan indeks sekunder lokal ke tabel yang sudah ada, Anda juga tidak dapat menghapus indeks sekunder lokal yang saat ini ada. | 
| Kueri dan Partisi | Indeks sekunder global memungkinkan Anda melakukan kueri di seluruh tabel, di semua partisi.  | Indeks sekunder lokal memungkinkan Anda melakukan kueri pada satu partisi, seperti yang ditentukan oleh nilai kunci partisi dalam kueri. | 
| Konsistensi Baca | Kueri pada indeks sekunder global hanya mendukung konsistensi akhir. | Saat Anda melakukan kueri indeks sekunder lokal, Anda dapat memilih konsistensi akhir atau konsistensi kuat. | 
| Konsumsi Throughput yang Disediakan | Setiap indeks sekunder global memiliki pengaturan throughput yang disediakan sendiri untuk aktivitas baca dan tulis. Kueri atau pemindaian pada indeks sekunder global menggunakan unit kapasitas dari indeks, bukan dari tabel dasar. Hal yang sama berlaku untuk pembaruan indeks sekunder global karena penulisan tabel. Indeks sekunder global yang terkait dengan tabel global mengonsumsi unit kapasitas tulis.  | Kueri atau pemindaian pada indeks sekunder lokal menggunakan unit kapasitas baca dari tabel dasar. Saat Anda menulis ke tabel, indeks sekunder lokalnya juga diperbarui, dan pembaruan ini menggunakan unit kapasitas tulis dari tabel dasar. Indeks sekunder lokal yang terkait dengan tabel global mengonsumsi unit kapasitas tulis. | 
| Atribut yang Diproyeksikan | Dengan kueri atau pemindaian indeks sekunder global, Anda hanya dapat meminta atribut yang diproyeksikan ke dalam indeks. DynamoDB tidak mengambil atribut apa pun dari tabel. | Jika Anda membuat kueri atau memindai indeks sekunder lokal, Anda dapat meminta atribut yang tidak diproyeksikan ke dalam indeks. DynamoDB secara otomatis mengambil atribut tersebut dari tabel. | 

Jika ingin membuat lebih dari satu tabel dengan indeks sekunder, Anda harus melakukannya secara berurutan. Misalnya, Anda akan membuat tabel pertama dan menunggu agar tabel menjadi `ACTIVE`, buat tabel berikutnya dan tunggu agar tabel menjadi `ACTIVE`, dan seterusnya. Jika Anda mencoba membuat lebih dari satu tabel secara bersamaan dengan indeks sekunder, DynamoDB mengembalikan `LimitExceededException`.

Setiap indeks sekunder menggunakan [kelas tabel](HowItWorks.TableClasses.html) dan [mode kapasitas](capacity-mode.md) yang sama dengan tabel dasar yang terkait dengannya. Untuk setiap indeks sekunder, Anda harus menentukan hal berikut:
+ Jenis indeks yang akan dibuat – baik indeks sekunder global atau indeks sekunder lokal.
+ Nama untuk indeks. Aturan penamaan untuk indeks sama dengan aturan untuk tabel, seperti yang tercantum dalam [Kuota di Amazon DynamoDB](ServiceQuotas.md). Nama harus unik untuk tabel dasar yang terkait dengannya, namun Anda dapat menggunakan nama yang sama untuk indeks yang terkait dengan tabel dasar berbeda.
+ Skema kunci indeks. Setiap atribut dalam skema kunci indeks harus merupakan atribut tingkat atas dari jenis `String`, `Number`, atau `Binary`. Jenis data lain, termasuk dokumen dan set, tidak diperbolehkan. Persyaratan lain untuk skema kunci bergantung pada jenis indeks: 
  + Untuk indeks sekunder global, kunci partisi dapat berupa atribut skalar apa pun dari tabel dasar. Kunci urutan bersifat opsional, dan dapat berupa atribut skalar apa pun dari tabel dasar.
  + Untuk indeks sekunder lokal, kunci partisi harus sama dengan kunci partisi tabel dasar, dan kunci urutan harus berupa atribut tabel dasar non-kunci.
+ Atribut tambahan, jika ada, untuk diproyeksikan dari tabel dasar ke dalam indeks. Atribut ini merupakan tambahan dari atribut kunci tabel, yang secara otomatis diproyeksikan ke dalam setiap indeks. Anda dapat memproyeksikan atribut dari jenis data apa pun, termasuk skalar, dokumen, dan set.
+ Pengaturan throughput yang disediakan untuk indeks, jika perlu:
  + Untuk indeks sekunder global, Anda harus menentukan pengaturan unit kapasitas baca dan tulis. Pengaturan throughput yang disediakan ini tidak tergantung pada pengaturan tabel dasar.
  + Untuk indeks sekunder lokal, Anda tidak perlu menentukan pengaturan unit kapasitas baca dan tulis. Setiap operasi baca dan tulis pada indeks sekunder lokal diambil dari pengaturan throughput yang disediakan dari tabel dasarnya.

Untuk fleksibilitas kueri maksimum, Anda dapat membuat hingga 20 indeks sekunder global (kuota default) dan hingga 5 indeks sekunder lokal per tabel.

Untuk mendapatkan daftar rinci indeks sekunder pada tabel, gunakan operasi `DescribeTable`. `DescribeTable` menampilkan nama, ukuran penyimpanan, dan jumlah item untuk setiap indeks sekunder pada tabel. Nilai-nilai ini tidak diperbarui secara real time, tetapi diperbarui kira-kira setiap enam jam.

Anda dapat mengakses data dalam indeks sekunder menggunakan operasi `Query` atau `Scan`. Kueri harus menentukan nama tabel dasar dan nama indeks yang ingin Anda gunakan, atribut yang akan dihasilkan dalam hasil kueri, dan syarat kueri apa pun yang ingin Anda terapkan. DynamoDB dapat menampilkan hasil dalam urutan menaik atau menurun.

Saat Anda menghapus tabel, semua indeks yang terkait dengan tabel tersebut juga akan dihapus.

Untuk praktik terbaik, lihat [Praktik terbaik untuk menggunakan indeks sekunder di DynamoDB](bp-indexes.md).

# Menggunakan Indeks Sekunder Global di DynamoDB
<a name="GSI"></a>

Beberapa aplikasi mungkin perlu melakukan banyak jenis kueri, menggunakan berbagai atribut berbeda sebagai kriteria kueri. Untuk mendukung persyaratan ini, Anda dapat membuat satu atau beberapa* indeks sekunder global* dan mengeluarkan permintaan `Query` terhadap indeks ini di Amazon DynamoDB.

**Topics**
+ [Skenario: Menggunakan Indeks Sekunder Global](#GSI.scenario)
+ [Proyeksi atribut](#GSI.Projections)
+ [Skema kunci multi-atribut](#GSI.MultiAttributeKeys)
+ [Membaca data dari Indeks Sekunder Global](#GSI.Reading)
+ [Sinkronisasi data antara tabel dan Indeks Sekunder Global](#GSI.Writes)
+ [Kelas tabel dengan Indeks Sekunder Global](#GSI.tableclasses)
+ [Pertimbangan Throughput yang disediakan untuk Indeks Sekunder Global](#GSI.ThroughputConsiderations)
+ [Pertimbangan penyimpanan untuk Indeks Sekunder Global](#GSI.StorageConsiderations)
+ [Pola desain](GSI.DesignPatterns.md)
+ [Mengelola Indeks Sekunder Global di DynamoDB](GSI.OnlineOps.md)
+ [Mendeteksi dan memperbaiki pelanggaran kunci indeks di DynamoDB](GSI.OnlineOps.ViolationDetection.md)
+ [Menggunakan Indeks Sekunder Global: Java](GSIJavaDocumentAPI.md)
+ [Menggunakan Indek Sekunder Global: .NET](GSILowLevelDotNet.md)
+ [Bekerja dengan Indeks Sekunder Global di DynamoDB menggunakan AWS CLI](GCICli.md)

## Skenario: Menggunakan Indeks Sekunder Global
<a name="GSI.scenario"></a>

Sebagai ilustrasi, pertimbangkan tabel bernama `GameScores` yang melacak pengguna dan skor untuk aplikasi game seluler. Setiap item dalam `GameScores` diidentifikasi dengan kunci partisi (`UserId`) dan kunci urutan (`GameTitle`). Diagram berikut menunjukkan bagaimana item dalam tabel akan diatur. (Tidak semua atribut ditampilkan.)

![\[GameScores tabel yang berisi daftar id pengguna, judul, skor, tanggal, dan kemenangan/kerugian.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/GSI_01.png)


Sekarang, anggaplah Anda ingin menulis aplikasi papan peringkat untuk menampilkan skor teratas untuk setiap game. Kueri yang menentukan atribut kunci (`UserId` dan `GameTitle`) akan sangat efisien. Namun, jika aplikasi perlu mengambil data dari `GameScores` berdasarkan `GameTitle` saja, aplikasi tersebut perlu menggunakan operasi `Scan`. Karena lebih banyak item ditambahkan ke tabel, pemindaian semua data akan lambat dan tidak efisien. Hal ini membuat pertanyaan-pertanyaan seperti berikut ini sulit dijawab:
+ Berapa skor tertinggi yang pernah tercatat untuk game Meteor Blasters?
+ Pengguna mana yang memiliki skor tertinggi untuk Galaxy Invaders?
+ Berapa rasio tertinggi untuk kemenangan vs kekalahan?

Untuk mempercepat kueri pada atribut non-kunci, Anda dapat membuat indeks sekunder global. Indeks sekunder global berisi pilihan atribut dari tabel dasar, tetapi atribut tersebut diatur oleh kunci primer yang berbeda dari tabel. Kunci indeks tidak perlu memiliki atribut kunci apa pun dari tabel. Bahkan tidak perlu memiliki skema kunci yang sama dengan tabel.

Misalnya, Anda dapat membuat indeks sekunder global bernama `GameTitleIndex`, dengan kunci partisi `GameTitle` dan kunci urutan `TopScore`. Atribut kunci primer tabel dasar selalu diproyeksikan ke dalam indeks, sehingga atribut `UserId` juga ada. Diagram berikut menunjukkan seperti apa tampilan indeks `GameTitleIndex`.

![\[GameTitleIndex tabel yang berisi daftar judul, skor, dan id pengguna.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/GSI_02.png)


Sekarang Anda dapat meminta `GameTitleIndex` dan dengan mudah mendapatkan skor untuk Meteor Blasters. Hasilnya diurutkan berdasarkan nilai kunci urutan, `TopScore`. Jika Anda mangatur parameter `ScanIndexForward` ke false, hasilnya ditampilkan dalam urutan menurun, sehingga skor tertinggi ditampilkan terlebih dahulu.

Setiap indeks sekunder global harus memiliki kunci partisi, dan dapat memiliki kunci urutan opsional. Skema kunci indeks dapat berbeda dari skema tabel dasar. Anda dapat memiliki tabel dengan kunci primer sederhana (kunci partisi), dan membuat indeks sekunder global dengan kunci primer komposit (kunci partisi dan kunci urutan)—atau sebaliknya. Atribut kunci indeks dapat terdiri dari atribut `String`, `Number`, atau `Binary` tingkat atas dari tabel dasar. Jenis skalar, jenis dokumen, dan jenis kumpulan lain tidak diperbolehkan.

Anda dapat memproyeksikan atribut tabel dasar lain ke dalam indeks jika ingin. Saat Anda mengkueri indeks, DynamoDB dapat mengambil atribut yang diproyeksikan ini secara efisien. Namun, kueri indeks sekunder global tidak dapat mengambil atribut dari tabel dasar. Misalnya, jika Anda mengkueri `GameTitleIndex` seperti yang ditunjukkan pada diagram sebelumnya, kueri tidak dapat mengakses atribut non-kunci selain `TopScore` (meskipun atribut kunci `GameTitle` dan `UserId` akan diproyeksikan secara otomatis).

Dalam tabel DynamoDB, setiap nilai kunci harus unik. Namun, nilai kunci dalam indeks sekunder global tidak perlu unik. Sebagai ilustrasi, anggaplah sebuah game bernama Comet Quest sangat sulit, dengan banyak pengguna baru yang telah mencoba tetapi gagal mendapatkan skor di atas nol. Berikut adalah beberapa data yang dapat mewakili hal tersebut.


****  

| UserId | GameTitle | TopScore | 
| --- | --- | --- | 
| 123 | Comet Quest | 0 | 
| 201 | Comet Quest | 0 | 
| 301 | Comet Quest | 0 | 

Ketika data ini ditambahkan ke tabel `GameScores`, DynamoDB menyebarkannya ke `GameTitleIndex`. Jika kita kemudian mengkueri indeks menggunakan Comet Quest untuk `GameTitle` dan 0 untuk `TopScore`, data berikut dikembalikan.

![\[Tabel berisi daftar judul, skor teratas, dan id pengguna.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/GSI_05.png)


Hanya item dengan nilai kunci tertentu yang muncul dalam respons. Dalam kumpulan data itu, item-item tersebut tidak berada dalam urutan tertentu. 

Indeks sekunder global hanya melacak item data yang atribut utamanya benar-benar ada. Misalnya, katakanlah Anda menambahkan item baru ke tabel `GameScores`, tetapi hanya menyediakan atribut kunci primer yang diperlukan.


****  

| UserId | GameTitle | 
| --- | --- | 
| 400 | Comet Quest | 

Karena Anda tidak menentukan atribut `TopScore`, DynamoDB tidak akan menyebarkan item ini ke `GameTitleIndex`. Jadi, jika mengkueri `GameScores` untuk semua item Comet Quest, Anda akan mendapatkan empat item berikut.

![\[Tabel berisi daftar 4 judul, skor teratas, dan id pengguna.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/GSI_04.png)


Kueri serupa pada `GameTitleIndex` masih akan mengembalikan tiga item, bukan empat. Ini karena item dengan `TopScore` yang tidak ada tidak disebarkan ke indeks.

![\[Tabel berisi daftar 3 judul, skor teratas, dan id pengguna.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/GSI_05.png)


## Proyeksi atribut
<a name="GSI.Projections"></a>

*Proyeksi* adalah kumpulan atribut yang disalin dari tabel ke indeks sekunder. Kunci partisi dan kunci urutan tabel selalu diproyeksikan ke dalam indeks; Anda dapat memproyeksikan atribut lain untuk mendukung persyaratan kueri aplikasi Anda. Saat Anda mengkueri indeks, Amazon DynamoDB dapat mengakses atribut apa pun dalam proyeksi seolah-olah atribut tersebut berada dalam tabelnya sendiri.

Saat membuat indeks sekunder, Anda perlu menentukan atribut yang akan diproyeksikan ke dalam indeks. DynamoDB menyediakan tiga opsi berbeda untuk ini:
+ *KEYS\$1ONLY* – Setiap item dalam indeks hanya terdiri dari kunci partisi tabel dan nilai kunci urutan, ditambah nilai kunci indeks. Opsi `KEYS_ONLY` menghasilkan indeks sekunder sekecil mungkin.
+ *INCLUDE* – Selain atribut yang dijelaskan dalam `KEYS_ONLY`, indeks sekunder akan menyertakan atribut non-kunci lain yang Anda tentukan.
+ *ALL* – Indeks sekunder menyertakan semua atribut dari tabel sumber. Karena semua data tabel diduplikasi dalam indeks, proyeksi `ALL` menghasilkan indeks sekunder sebesar yang mungkin.

Pada diagram sebelumnya, `GameTitleIndex` hanya memiliki satu atribut yang diproyeksikan: `UserId`. Jadi, meskipun aplikasi dapat secara efisien menentukan `UserId` dari pencetak skor terbanyak untuk setiap game menggunakan `GameTitle` dan `TopScore` dalam kueri, aplikasi tidak dapat secara efisien menentukan rasio kemenangan vs. kekalahan tertinggi untuk pencetak skor terbanyak. Untuk melakukannya, aplikasi harus melakukan kueri tambahan di tabel dasar untuk mengambil kemenangan dan kerugian untuk masing-masing pencetak gol terbanyak. Cara yang lebih efisien untuk mendukung kueri pada data ini adalah dengan memproyeksikan atribut-atribut ini dari tabel dasar ke dalam indeks sekunder global, seperti yang ditunjukkan dalam diagram ini. 

![\[Penggambaran memproyeksikan atribut non-kunci ke dalam GSI untuk mendukung kueri yang efisien.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/GSI_06.png)


Karena atribut non-kunci `Wins` dan `Losses` diproyeksikan ke dalam indeks, aplikasi dapat menentukan rasio kemenangan vs. kekalahan untuk game apa pun, atau untuk kombinasi game dan ID pengguna mana pun.

Saat memilih atribut untuk diproyeksikan ke dalam indeks sekunder global, Anda harus mempertimbangkan tradeoff antara biaya throughput yang disediakan dan biaya penyimpanan:
+ Jika Anda hanya perlu mengakses beberapa atribut dengan latensi serendah mungkin, pertimbangkan untuk hanya memproyeksikan atribut tersebut ke dalam indeks sekunder global. Semakin kecil indeks, semakin sedikit biaya penyimpanannya, dan semakin sedikit pula biaya tulis Anda.
+ Jika aplikasi Anda sering mengakses beberapa atribut non-kunci, sebaiknya Anda memproyeksikan atribut tersebut ke dalam indeks sekunder global. Biaya penyimpanan tambahan untuk indeks sekunder global mengimbangi biaya melakukan pemindaian tabel yang sering dilakukan.
+ Jika sering mengakses sebagian besar atribut non-kunci, Anda dapat memproyeksikan atribut ini—atau bahkan seluruh tabel dasar— ke dalam indeks sekunder global. Hal ini akan memberi Anda fleksibilitas maksimum. Namun, biaya penyimpanan Anda akan meningkat, atau bahkan berlipat ganda.
+ Jika aplikasi Anda jarang mengkueri tabel, tetapi harus melakukan banyak penulisan atau pembaruan terhadap data dalam tabel, pertimbangkan untuk memproyeksikan `KEYS_ONLY`. Indeks sekunder global akan berukuran minimal, tetapi akan tetap tersedia jika diperlukan untuk aktivitas kueri. 

## Skema kunci multi-atribut
<a name="GSI.MultiAttributeKeys"></a>

Global Secondary Indexes mendukung kunci multi-atribut, memungkinkan Anda untuk membuat kunci partisi dan mengurutkan kunci dari beberapa atribut. Dengan kunci multi-atribut, Anda dapat membuat kunci partisi dari hingga empat atribut dan kunci pengurutan dari hingga empat atribut, dengan total hingga delapan atribut per skema kunci.

Kunci multi-atribut menyederhanakan model data Anda dengan menghilangkan kebutuhan untuk menggabungkan atribut secara manual menjadi kunci sintetis. Alih-alih membuat string komposit seperti`TOURNAMENT#WINTER2024#REGION#NA-EAST`, Anda dapat menggunakan atribut alami dari model domain Anda secara langsung. DynamoDB menangani logika kunci komposit secara otomatis, melakukan hashing beberapa atribut kunci partisi bersama-sama untuk distribusi data dan mempertahankan urutan pengurutan hierarkis di beberapa atribut kunci pengurutan.

Misalnya, pertimbangkan sistem turnamen game di mana Anda ingin mengatur pertandingan berdasarkan turnamen dan wilayah. Dengan kunci multi-atribut, Anda dapat mendefinisikan kunci partisi Anda sebagai dua atribut terpisah: `tournamentId` dan`region`. Demikian pula, Anda dapat menentukan kunci pengurutan Anda menggunakan beberapa atribut seperti `round``bracket`,, dan `matchId` untuk membuat hierarki alami. Pendekatan ini membuat data Anda diketik dan kode Anda bersih, tanpa manipulasi string atau penguraian.

Saat Anda menanyakan indeks sekunder global dengan kunci multi-atribut, Anda harus menentukan semua atribut kunci partisi menggunakan kondisi kesetaraan. Untuk mengurutkan atribut kunci, Anda dapat menanyakannya left-to-right dalam urutan yang ditentukan dalam skema kunci. Ini berarti Anda dapat menanyakan atribut kunci sortir pertama saja, dua atribut pertama bersama-sama, atau semua atribut bersama-sama, tetapi Anda tidak dapat melewati atribut di tengah. Kondisi ketidaksetaraan seperti`>`,`<`,`BETWEEN`, atau `begins_with()` harus menjadi kondisi terakhir dalam kueri Anda.

Kunci multi-atribut bekerja sangat baik saat membuat indeks sekunder global pada tabel yang ada. Anda dapat menggunakan atribut yang sudah ada di tabel Anda tanpa mengisi kembali kunci sintetis di seluruh data Anda. Ini membuatnya mudah untuk menambahkan pola kueri baru ke aplikasi Anda dengan membuat indeks yang mengatur ulang data Anda menggunakan kombinasi atribut yang berbeda.

Setiap atribut dalam kunci multi-atribut dapat memiliki tipe datanya sendiri: `String` (S), `Number` (N), atau `Binary` (B). Saat memilih tipe data, pertimbangkan bahwa `Number` atribut mengurutkan secara numerik tanpa memerlukan padding nol, sementara atribut mengurutkan secara leksikografis. `String` Misalnya, jika Anda menggunakan `Number` tipe untuk atribut skor, nilai 5, 50, 500, dan 1000 diurutkan dalam urutan numerik alami. Nilai yang sama dengan `String` tipe akan diurutkan sebagai “1000", “5", “50", “500" kecuali Anda menutupinya dengan angka nol di depan.

Saat mendesain kunci multi-atribut, urutkan atribut Anda dari yang paling umum ke yang paling spesifik. Untuk kunci partisi, gabungkan atribut yang selalu ditanyakan bersama dan yang menyediakan distribusi data yang baik. Untuk kunci sortir, tempatkan atribut yang sering ditanyakan terlebih dahulu dalam hierarki untuk memaksimalkan fleksibilitas kueri. Urutan ini memungkinkan Anda untuk menanyakan pada tingkat perincian apa pun yang cocok dengan pola akses Anda.

Lihat [Kunci multi-atribut](GSI.DesignPattern.MultiAttributeKeys.md) contoh implementasi untuk.

## Membaca data dari Indeks Sekunder Global
<a name="GSI.Reading"></a>

Anda dapat mengambil item dari indeks sekunder global menggunakan operasi `Query` dan `Scan`. Operasi `GetItem` dan `BatchGetItem` tidak dapat digunakan pada indeks sekunder global.

### Mengkueri Indeks Sekunder Global
<a name="GSI.Querying"></a>

Anda dapat menggunakan operasi `Query` untuk mengakses satu atau beberapa item dalam indeks sekunder global. Kueri harus menentukan nama tabel dasar dan nama indeks yang ingin Anda gunakan, atribut yang akan dihasilkan dalam hasil kueri, dan syarat kueri apa pun yang ingin Anda terapkan. DynamoDB dapat menampilkan hasil dalam urutan menaik atau menurun.

Pertimbangkan data berikut yang dihasilkan dari `Query` yang meminta data game untuk aplikasi papan peringkat.

```
{
    "TableName": "GameScores",
    "IndexName": "GameTitleIndex",
    "KeyConditionExpression": "GameTitle = :v_title",
    "ExpressionAttributeValues": {
        ":v_title": {"S": "Meteor Blasters"}
    },
    "ProjectionExpression": "UserId, TopScore",
    "ScanIndexForward": false
}
```

Dalam kueri ini:
+ DynamoDB *GameTitleIndex*mengakses, menggunakan kunci partisi untuk menemukan *GameTitle*item indeks untuk Meteor Blasters. Semua item indeks dengan kunci ini disimpan berdekatan satu sama lain untuk pengambilan cepat.
+ Dalam game ini, DynamoDB menggunakan indeks untuk mengakses semua IDs pengguna dan skor teratas untuk game ini.
+ Hasilnya ditampilkan dalam urutan menurun karena parameter `ScanIndexForward` diatur ke false.

### Memindai Indeks Sekunder Global
<a name="GSI.Scanning"></a>

Anda dapat menggunakan operasi `Scan` untuk mengambil semua data dari indeks sekunder global. Anda harus memberikan nama tabel dasar dan nama indeks dalam permintaan. Dengan `Scan`, DynamoDB membaca semua data dalam indeks dan mengembalikannya ke aplikasi. Anda juga dapat meminta agar hanya sebagian data yang dikembalikan, dan data yang tersisa harus dibuang. Untuk melakukannya, gunakan parameter `FilterExpression` dari operasi `Scan`. Untuk informasi selengkapnya, lihat [Ekspresi filter untuk pemindaian](Scan.md#Scan.FilterExpression).

## Sinkronisasi data antara tabel dan Indeks Sekunder Global
<a name="GSI.Writes"></a>

DynamoDB otomatis menyinkronkan setiap indeks sekunder global dengan tabel dasarnya. Saat aplikasi menulis atau menghapus item dalam tabel, indeks sekunder global apa pun di tabel tersebut diperbarui secara asinkron, menggunakan model yang akhirnya konsisten. Aplikasi tidak pernah menulis langsung ke indeks. Namun, Anda harus memahami implikasi dari cara DynamoDB mempertahankan indeks ini.

 Indeks sekunder global mewarisi mode read/write kapasitas dari tabel dasar. Untuk informasi selengkapnya, lihat [Pertimbangan saat mengganti mode kapasitas di DynamoDB](bp-switching-capacity-modes.md). 

Saat membuat indeks sekunder global, Anda menentukan satu atau beberapa atribut kunci indeks dan jenis datanya. Ini berarti bahwa setiap kali Anda menulis item ke tabel dasar, jenis data untuk atribut tersebut harus cocok dengan jenis data skema kunci indeks. Dalam kasus `GameTitleIndex`, kunci partisi `GameTitle` dalam indeks didefinisikan sebagai jenis data `String`. Kunci urutan `TopScore` dalam indeks adalah jenis `Number`. Jika Anda mencoba menambahkan item ke tabel `GameScores` dan menentukan jenis data yang berbeda untuk `GameTitle` atau `TopScore`, DynamoDB mengembalikan `ValidationException` karena jenis data tidak cocok.

Saat Anda memasukkan atau menghapus item dalam tabel, indeks sekunder global pada tabel tersebut diperbarui secara konsisten. Perubahan pada data tabel disebarkan ke indeks sekunder global dalam sepersekian detik, dalam kondisi normal. Namun, dalam beberapa skenario kegagalan yang tidak terduga, penundaan penyebaran yang lebih lama mungkin terjadi. Oleh karena itu, aplikasi Anda perlu mengantisipasi dan menangani situasi ketika kueri pada indeks sekunder global mengembalikan hasil yang tidak mutakhir.

Jika menulis item ke tabel, Anda tidak perlu menentukan atribut untuk kunci urutan indeks sekunder global. Menggunakan `GameTitleIndex`, misalnya, Anda tidak perlu menentukan nilai atribut `TopScore` untuk menulis item baru ke tabel `GameScores`. Dalam hal ini, DynamoDB tidak menulis data apa pun ke indeks untuk item khusus ini.

Tabel dengan banyak indeks sekunder global menimbulkan biaya lebih tinggi untuk aktivitas tulis dibandingkan tabel dengan lebih sedikit indeks. Untuk informasi selengkapnya, lihat [Pertimbangan Throughput yang disediakan untuk Indeks Sekunder Global](#GSI.ThroughputConsiderations).

## Kelas tabel dengan Indeks Sekunder Global
<a name="GSI.tableclasses"></a>

Indeks sekunder global akan selalu menggunakan kelas tabel yang sama dengan tabel dasarnya. Setiap kali indeks sekunder global baru ditambahkan untuk tabel, indeks baru akan menggunakan kelas tabel yang sama dengan tabel dasarnya. Ketika kelas tabel diperbarui, semua indeks sekunder global terkait juga diperbarui.

## Pertimbangan Throughput yang disediakan untuk Indeks Sekunder Global
<a name="GSI.ThroughputConsiderations"></a>

Saat membuat indeks sekunder global pada tabel mode yang disediakan, Anda harus menentukan unit kapasitas baca dan tulis untuk beban kerja yang diharapkan pada indeks tersebut. Pengaturan throughput yang disediakan pada indeks sekunder global terpisah dari pengaturan tabel dasarnya. Operasi `Query` pada indeks sekunder global menggunakan unit kapasitas baca dari indeks, bukan tabel dasar. Saat Anda memasukkan, memperbarui, atau menghapus item dalam tabel, indeks sekunder global pada tabel tersebut juga diperbarui. Pembaruan indeks ini menggunakan unit kapasitas tulis dari indeks, bukan dari tabel dasar.

Misalnya, jika Anda `Query` indeks sekunder global dan melebihi kapasitas baca yang disediakan, permintaan Anda akan mengalami throttling. Jika Anda melakukan aktivitas tulis berat pada tabel, tetapi indeks sekunder global pada tabel tersebut memiliki kapasitas tulis yang tidak memadai, aktivitas tulis pada tabel akan mengalami throttling.

**penting**  
 Untuk menghindari potensi throttling, kapasitas tulis yang disediakan untuk indeks sekunder global harus sama atau lebih besar dari kapasitas tulis tabel dasar karena pembaruan baru menulis ke tabel dasar dan indeks sekunder global. 

Untuk melihat pengaturan throughput yang disediakan untuk indeks sekunder global, gunakan operasi `DescribeTable`. Informasi mendetail tentang semua indeks sekunder global tabel ditampilkan.

### Unit kapasitas baca
<a name="GSI.ThroughputConsiderations.Reads"></a>

Indeks sekunder global mendukung bacaan akhir konsisten, yang masing-masing menggunakan setengah dari unit kapasitas baca. Artinya, satu kueri indeks sekunder global dapat mengambil hingga 2 × 4 KB = 8 KB per unit kapasitas baca.

Untuk kueri indeks sekunder global, DynamoDB menghitung aktivitas baca yang disediakan dengan cara yang sama seperti kueri terhadap tabel. Satu-satunya hal yang membedakan adalah penghitungan didasarkan pada ukuran entri indeks, bukan ukuran item dalam tabel dasar. Jumlah unit kapasitas baca adalah jumlah dari semua ukuran atribut yang diproyeksikan di semua item yang dikembalikan. Hasilnya kemudian dibulatkan ke batas 4 KB berikutnya. Untuk informasi selengkapnya tentang cara DynamoDB menghitung penggunaan throughput yang disediakan, lihat [DynamoDB menyediakan mode kapasitas](provisioned-capacity-mode.md).

Ukuran maksimum hasil yang dikembalikan oleh operasi `Query` adalah 1 MB. Ini termasuk ukuran semua nama dan nilai atribut di semua item yang dikembalikan.

Misalnya, pertimbangkan indeks sekunder global yang setiap itemnya berisi 2.000 byte data. Sekarang, anggaplah Anda `Query` indeks ini dan `KeyConditionExpression` kueri cocok dengan delapan item. Ukuran total item yang cocok adalah 2.000 byte × 8 item = 16.000 byte. Hasil ini kemudian dibulatkan ke batas 4 KB terdekat. Karena kueri indeks sekunder global pada akhirnya konsisten, biaya totalnya adalah 0,5 × (16 KB / 4 KB), atau 2 unit kapasitas baca.

### Unit kapasitas tulis
<a name="GSI.ThroughputConsiderations.Writes"></a>

Ketika item dalam tabel ditambahkan, diperbarui, atau dihapus, dan indeks sekunder global terpengaruh oleh ini, indeks sekunder global menggunakan unit kapasitas tulis yang disediakan untuk operasi. Total biaya throughput yang disediakan untuk penulisan terdiri dari jumlah unit kapasitas tulis yang digunakan dengan menulis ke tabel dasar dan yang digunakan dengan memperbarui indeks sekunder global. Jika penulisan ke tabel tidak memerlukan pembaruan indeks sekunder global, tidak ada kapasitas tulis yang digunakan dari indeks.

Agar penulisan tabel berhasil, pengaturan throughput yang disediakan untuk tabel dan semua indeks sekunder globalnya harus memiliki kapasitas tulis yang memadai untuk mengakomodasi penulisan. Jika tidak, penulisan ke tabel akan mengalami throttling. 

**penting**  
Saat membuat Indeks Sekunder Global (GSI), operasi tulis ke tabel dasar dapat dibatasi jika aktivitas GSI yang dihasilkan dari penulisan ke tabel dasar melebihi kapasitas tulis yang disediakan GSI. Pelambatan ini memengaruhi semua operasi penulisan, mulai dari proses pengindeksan hingga berpotensi mengganggu beban kerja produksi Anda. Untuk informasi selengkapnya, lihat [Pemecahan masalah pembatasan di Amazon](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TroubleshootingThrottling.html) DynamoDB.

Biaya tulis item ke indeks sekunder global tergantung pada beberapa faktor:
+ Jika Anda menulis item baru ke tabel yang menentukan atribut yang diindeks, atau Anda memperbarui item yang ada untuk menentukan atribut terindeks yang sebelumnya tidak ditentukan, satu operasi tulis diperlukan untuk memasukkan item ke dalam indeks.
+ Jika pembaruan pada tabel mengubah nilai atribut kunci yang diindeks (dari A menjadi B), diperlukan dua penulisan, satu untuk menghapus item sebelumnya dari indeks dan satu lagi untuk memasukkan item baru ke dalam indeks.  
+ Jika suatu item ada dalam indeks, tetapi penulisan ke tabel menyebabkan atribut yang diindeks terhapus, satu penulisan diperlukan untuk menghapus proyeksi item lama dari indeks.
+ Jika item tidak ada dalam indeks sebelum atau setelah item diperbarui, tidak ada biaya penulisan tambahan untuk indeks tersebut.
+ Jika pembaruan pada tabel hanya mengubah nilai atribut yang diproyeksikan dalam skema kunci indeks, tetapi tidak mengubah nilai atribut kunci yang diindeks, satu penulisan diperlukan untuk memperbarui nilai atribut yang diproyeksikan ke dalam indeks.

Semua faktor ini mengasumsikan bahwa ukuran setiap item dalam indeks kurang dari atau sama dengan ukuran item 1 KB untuk menghitung unit kapasitas tulis. Entri indeks yang lebih besar memerlukan unit kapasitas tulis tambahan. Anda dapat meminimalkan biaya penulisan dengan mempertimbangkan atribut yang perlu dikembalikan oleh kueri dan hanya memproyeksikan atribut tersebut ke dalam indeks.

## Pertimbangan penyimpanan untuk Indeks Sekunder Global
<a name="GSI.StorageConsiderations"></a>

Saat aplikasi menulis item ke tabel, DynamoDB otomatis menyalin subset atribut yang benar ke indeks sekunder global tempat atribut tersebut akan muncul. AWS Akun Anda dikenakan biaya untuk penyimpanan item di tabel dasar dan juga untuk penyimpanan atribut dalam indeks sekunder global apa pun di tabel itu.

Jumlah ruang yang digunakan oleh item indeks adalah jumlah dari berikut ini:
+ Ukuran kunci primer tabel dasar dalam byte (kunci partisi dan kunci urutan)
+ Ukuran atribut kunci indeks dalam byte
+ Ukuran atribut yang diproyeksikan dalam byte (jika ada)
+ 100 byte dari overhead per item indeks

Untuk memperkirakan kebutuhan penyimpanan indeks sekunder global, Anda dapat memperkirakan ukuran rata-rata item dalam indeks lalu mengalikannya dengan jumlah item dalam tabel dasar yang memiliki atribut kunci indeks sekunder global.

Jika tabel berisi item di mana atribut tertentu tidak didefinisikan, tetapi atribut tersebut didefinisikan sebagai kunci partisi indeks atau kunci sortir, DynamoDB tidak menulis data apa pun untuk item tersebut ke indeks.

# Pola desain
<a name="GSI.DesignPatterns"></a>

Pola desain memberikan solusi yang terbukti untuk tantangan umum saat bekerja dengan indeks sekunder global. Pola-pola ini membantu Anda membangun aplikasi yang efisien dan dapat diskalakan dengan menunjukkan kepada Anda cara menyusun indeks Anda untuk kasus penggunaan tertentu.

Setiap pola menyertakan panduan implementasi lengkap dengan contoh kode, praktik terbaik, dan kasus penggunaan dunia nyata untuk membantu Anda menerapkan pola ke aplikasi Anda sendiri.

**Topics**
+ [Kunci multi-atribut](GSI.DesignPattern.MultiAttributeKeys.md)

# Pola kunci multi-atribut
<a name="GSI.DesignPattern.MultiAttributeKeys"></a>

## Gambaran umum
<a name="GSI.DesignPattern.MultiAttributeKeys.Overview"></a>

Kunci multi-atribut memungkinkan Anda membuat partisi Global Secondary Index (GSI) dan mengurutkan kunci masing-masing terdiri dari hingga empat atribut. Ini mengurangi kode sisi klien dan membuatnya lebih mudah untuk awalnya memodelkan data dan menambahkan pola akses baru nanti.

Pertimbangkan skenario umum: untuk membuat GSI yang menanyakan item dengan beberapa atribut hierarkis, Anda secara tradisional perlu membuat kunci sintetis dengan menggabungkan nilai. Misalnya, dalam aplikasi game, untuk menanyakan pertandingan turnamen berdasarkan turnamen, wilayah, dan putaran, Anda dapat membuat kunci partisi GSI sintetis seperti TURNAMEN \$1 WINTER2 024 \$1REGION \$1NA -EAST dan kunci pengurutan sintetis seperti ROUND \$1SEMIFINALS \$1BRACKET \$1UPPER. Pendekatan ini berfungsi, tetapi memerlukan penggabungan string saat menulis data, mengurai saat membaca, dan mengisi kembali kunci sintetis di semua item yang ada jika Anda menambahkan GSI ke tabel yang ada. Hal ini membuat kode lebih berantakan dan menantang untuk menjaga keamanan tipe pada masing-masing komponen kunci.

Kunci multi-atribut memecahkan masalah ini untuk GSIs. Anda menentukan kunci partisi GSI Anda menggunakan beberapa atribut yang ada seperti TournamentID dan wilayah. DynamoDB menangani logika kunci komposit secara otomatis, hashing mereka bersama-sama untuk distribusi data. Anda menulis item menggunakan atribut alami dari model domain Anda, dan GSI secara otomatis mengindeksnya. Tidak ada penggabungan, tidak ada penguraian, tidak ada penimbunan ulang. Kode Anda tetap bersih, data Anda tetap diketik, dan kueri Anda tetap sederhana. Pendekatan ini sangat berguna ketika Anda memiliki data hierarkis dengan pengelompokan atribut alami (seperti turnamen → wilayah → putaran, atau organisasi → departemen → tim).

## Contoh aplikasi
<a name="GSI.DesignPattern.MultiAttributeKeys.ApplicationExample"></a>

Panduan ini berjalan melalui pembangunan sistem pelacakan pertandingan turnamen untuk platform esports. Platform perlu menanyakan kecocokan secara efisien di berbagai dimensi: berdasarkan turnamen dan wilayah untuk manajemen braket, oleh pemain untuk riwayat pertandingan, dan berdasarkan tanggal untuk penjadwalan.

## Model Data
<a name="GSI.DesignPattern.MultiAttributeKeys.DataModel"></a>

Dalam panduan ini, sistem pelacakan pertandingan turnamen mendukung tiga pola akses utama, masing-masing membutuhkan struktur kunci yang berbeda:

**Pola akses 1:** Cari kecocokan tertentu berdasarkan ID uniknya
+ **Solusi:** Tabel dasar dengan `matchId` kunci partisi

**Pola akses 2:** Kueri semua pertandingan untuk turnamen dan wilayah tertentu, secara opsional memfilter berdasarkan putaran, braket, atau pertandingan
+ **Solusi:** Indeks Sekunder Global dengan kunci partisi multi-atribut (`tournamentId`\$1`region`) dan kunci pengurutan multi-atribut (`round`\$1 \$1`bracket`) `matchId`
+ **Contoh kueri:** “Semua WINTER2 024 pertandingan di wilayah NA-EAST” atau “Semua Semifinal cocok di braket UPPER untuk 024/NA-EAST” WINTER2

**Pola akses 3:** Menanyakan riwayat pertandingan pemain, secara opsional memfilter berdasarkan rentang tanggal atau putaran turnamen
+ **Solusi:** Indeks Sekunder Global dengan kunci partisi tunggal (`player1Id`) dan kunci pengurutan multi-atribut (`matchDate`\$1`round`)
+ **Contoh pertanyaan:** “Semua pertandingan untuk pemain 101" atau “Pertandingan Pemain 101 pada Januari 2024"

Perbedaan utama antara pendekatan tradisional dan multi-atribut menjadi jelas saat memeriksa struktur item:

**Pendekatan Indeks Sekunder Global Tradisional (kunci gabungan):**

```
// Manual concatenation required for GSI keys
const item = {
    matchId: 'match-001',                                          // Base table PK
    tournamentId: 'WINTER2024',
    region: 'NA-EAST',
    round: 'SEMIFINALS',
    bracket: 'UPPER',
    player1Id: '101',
    // Synthetic keys needed for GSI
    GSI_PK: `TOURNAMENT#${tournamentId}#REGION#${region}`,       // Must concatenate
    GSI_SK: `${round}#${bracket}#${matchId}`,                    // Must concatenate
    // ... other attributes
};
```

**Pendekatan Indeks Sekunder Global multi-atribut (kunci asli):**

```
// Use existing attributes directly - no concatenation needed
const item = {
    matchId: 'match-001',                                          // Base table PK
    tournamentId: 'WINTER2024',
    region: 'NA-EAST',
    round: 'SEMIFINALS',
    bracket: 'UPPER',
    player1Id: '101',
    matchDate: '2024-01-18',
    // No synthetic keys needed - GSI uses existing attributes directly
    // ... other attributes
};
```

Dengan kunci multi-atribut, Anda menulis item sekali dengan atribut domain alami. DynamoDB secara otomatis mengindeks mereka di GSIs beberapa tanpa memerlukan kunci gabungan sintetis.

**Skema tabel dasar:**
+ Kunci partisi: `matchId` (1 atribut)

**Skema Indeks Sekunder Global (TournamentRegionIndex dengan kunci multi-atribut):**
+ Kunci partisi:`tournamentId`, `region` (2 atribut)
+ Kunci sortir:`round`,`bracket`, `matchId` (3 atribut)

**Skema Indeks Sekunder Global (PlayerMatchHistoryIndex dengan kunci multi-atribut):**
+ Kunci partisi: `player1Id` (1 atribut)
+ Kunci sortir:`matchDate`, `round` (2 atribut)

### Tabel dasar: TournamentMatches
<a name="GSI.DesignPattern.MultiAttributeKeys.BaseTable"></a>


| MatchID (PK) | TurnamenID | region | bulat | tanda kurung | Player1id | Player2id | MatchDate | pemenang | skor | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| pertandingan-001 | WINTER2024 | NA-TIMUR | FINAL | KEJUARAAN | 101 | 103 | 2024-01-20 | 101 | 3-1 | 
| pertandingan-002 | WINTER2024 | NA-TIMUR | SEMIFINAL | ATAS | 101 | 105 | 2024-01-18 | 101 | 3-2 | 
| pertandingan-003 | WINTER2024 | NA-TIMUR | SEMIFINAL | ATAS | 103 | 107 | 2024-01-18 | 103 | 3-0 | 
| pertandingan-004 | WINTER2024 | NA-TIMUR | PEREMPAT FINAL | ATAS | 101 | 109 | 2024-01-15 | 101 | 3-1 | 
| pertandingan-005 | WINTER2024 | NA-BARAT | FINAL | KEJUARAAN | 102 | 104 | 2024-01-20 | 102 | 3-2 | 
| pertandingan-006 | WINTER2024 | NA-BARAT | SEMIFINAL | ATAS | 102 | 106 | 2024-01-18 | 102 | 3-1 | 
| pertandingan-007 | SPRING2024 | NA-TIMUR | PEREMPAT FINAL | ATAS | 101 | 108 | 2024-03-15 | 101 | 3-0 | 
| pertandingan-008 | SPRING2024 | NA-TIMUR | PEREMPAT FINAL | LEBIH RENDAH | 103 | 110 | 2024-03-15 | 103 | 3-2 | 

### GSI: TournamentRegionIndex (kunci multi-atribut)
<a name="GSI.DesignPattern.MultiAttributeKeys.TournamentRegionIndexTable"></a>


| TurnamenID (PK) | wilayah (PK) | bulat (SK) | braket (SK) | MatchID (SK) | Player1id | Player2id | MatchDate | pemenang | skor | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| WINTER2024 | NA-TIMUR | FINAL | KEJUARAAN | pertandingan-001 | 101 | 103 | 2024-01-20 | 101 | 3-1 | 
| WINTER2024 | NA-TIMUR | PEREMPAT FINAL | ATAS | pertandingan-004 | 101 | 109 | 2024-01-15 | 101 | 3-1 | 
| WINTER2024 | NA-TIMUR | SEMIFINAL | ATAS | pertandingan-002 | 101 | 105 | 2024-01-18 | 101 | 3-2 | 
| WINTER2024 | NA-TIMUR | SEMIFINAL | ATAS | pertandingan-003 | 103 | 107 | 2024-01-18 | 103 | 3-0 | 
| WINTER2024 | NA-BARAT | FINAL | KEJUARAAN | pertandingan-005 | 102 | 104 | 2024-01-20 | 102 | 3-2 | 
| WINTER2024 | NA-BARAT | SEMIFINAL | ATAS | pertandingan-006 | 102 | 106 | 2024-01-18 | 102 | 3-1 | 
| SPRING2024 | NA-TIMUR | PEREMPAT FINAL | LEBIH RENDAH | pertandingan-008 | 103 | 110 | 2024-03-15 | 103 | 3-2 | 
| SPRING2024 | NA-TIMUR | PEREMPAT FINAL | ATAS | pertandingan-007 | 101 | 108 | 2024-03-15 | 101 | 3-0 | 

### GSI: PlayerMatchHistoryIndex (kunci multi-atribut)
<a name="GSI.DesignPattern.MultiAttributeKeys.PlayerMatchHistoryIndexTable"></a>


| Player1ID (PK) | MatchDate (SK) | bulat (SK) | TurnamenID | region | tanda kurung | MatchID | Player2id | pemenang | skor | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| 101 | 2024-01-15 | PEREMPAT FINAL | WINTER2024 | NA-TIMUR | ATAS | pertandingan-004 | 109 | 101 | 3-1 | 
| 101 | 2024-01-18 | SEMIFINAL | WINTER2024 | NA-TIMUR | ATAS | pertandingan-002 | 105 | 101 | 3-2 | 
| 101 | 2024-01-20 | FINAL | WINTER2024 | NA-TIMUR | KEJUARAAN | pertandingan-001 | 103 | 101 | 3-1 | 
| 101 | 2024-03-15 | PEREMPAT FINAL | SPRING2024 | NA-TIMUR | ATAS | pertandingan-007 | 108 | 101 | 3-0 | 
| 102 | 2024-01-18 | SEMIFINAL | WINTER2024 | NA-BARAT | ATAS | pertandingan-006 | 106 | 102 | 3-1 | 
| 102 | 2024-01-20 | FINAL | WINTER2024 | NA-BARAT | KEJUARAAN | pertandingan-005 | 104 | 102 | 3-2 | 
| 103 | 2024-01-18 | SEMIFINAL | WINTER2024 | NA-TIMUR | ATAS | pertandingan-003 | 107 | 103 | 3-0 | 
| 103 | 2024-03-15 | PEREMPAT FINAL | SPRING2024 | NA-TIMUR | LEBIH RENDAH | pertandingan-008 | 110 | 103 | 3-2 | 

## Prasyarat
<a name="GSI.DesignPattern.MultiAttributeKeys.Prerequisites"></a>

Sebelum Anda mulai, pastikan Anda memiliki:

### Akun dan izin
<a name="GSI.DesignPattern.MultiAttributeKeys.Prerequisites.AWSAccount"></a>
+  AWS Akun aktif ([buat satu di sini](https://aws.amazon.com/free/) jika diperlukan)
+ Izin IAM untuk operasi DynamoDB:
  + `dynamodb:CreateTable`
  + `dynamodb:DeleteTable`
  + `dynamodb:DescribeTable`
  + `dynamodb:PutItem`
  + `dynamodb:Query`
  + `dynamodb:BatchWriteItem`

**catatan**  
**Catatan Keamanan:** Untuk penggunaan produksi, buat kebijakan IAM khusus hanya dengan izin yang Anda butuhkan. Untuk tutorial ini, Anda dapat menggunakan kebijakan AWS terkelola`AmazonDynamoDBFullAccessV2`.

### Lingkungan Pengembangan
<a name="GSI.DesignPattern.MultiAttributeKeys.Prerequisites.DevEnvironment"></a>
+ Node.js diinstal pada mesin Anda
+ AWS kredensil yang dikonfigurasi menggunakan salah satu metode ini:

**Opsi 1: AWS CLI**

```
aws configure
```

**Opsi 2: Variabel Lingkungan**

```
export AWS_ACCESS_KEY_ID=your_access_key_here
export AWS_SECRET_ACCESS_KEY=your_secret_key_here
export AWS_DEFAULT_REGION=us-east-1
```

### Instal Paket yang Diperlukan
<a name="GSI.DesignPattern.MultiAttributeKeys.Prerequisites.InstallPackages"></a>

```
npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
```

## Implementasi
<a name="GSI.DesignPattern.MultiAttributeKeys.Implementation"></a>

### Langkah 1: Buat tabel dengan GSIs menggunakan tombol multi-atribut
<a name="GSI.DesignPattern.MultiAttributeKeys.CreateTable"></a>

Buat tabel dengan struktur kunci dasar sederhana dan GSIs yang menggunakan kunci multi-atribut.

#### Contoh kode
<a name="w2aac19c13c45c23b9c11b3b5b1"></a>

```
import { DynamoDBClient, CreateTableCommand } from "@aws-sdk/client-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });

const response = await client.send(new CreateTableCommand({
    TableName: 'TournamentMatches',
    
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'matchId', KeyType: 'HASH' }              // Simple PK
    ],
    
    AttributeDefinitions: [
        { AttributeName: 'matchId', AttributeType: 'S' },
        { AttributeName: 'tournamentId', AttributeType: 'S' },
        { AttributeName: 'region', AttributeType: 'S' },
        { AttributeName: 'round', AttributeType: 'S' },
        { AttributeName: 'bracket', AttributeType: 'S' },
        { AttributeName: 'player1Id', AttributeType: 'S' },
        { AttributeName: 'matchDate', AttributeType: 'S' }
    ],
    
    // GSIs with multi-attribute keys
    GlobalSecondaryIndexes: [
        {
            IndexName: 'TournamentRegionIndex',
            KeySchema: [
                { AttributeName: 'tournamentId', KeyType: 'HASH' },    // GSI PK attribute 1
                { AttributeName: 'region', KeyType: 'HASH' },          // GSI PK attribute 2
                { AttributeName: 'round', KeyType: 'RANGE' },          // GSI SK attribute 1
                { AttributeName: 'bracket', KeyType: 'RANGE' },        // GSI SK attribute 2
                { AttributeName: 'matchId', KeyType: 'RANGE' }         // GSI SK attribute 3
            ],
            Projection: { ProjectionType: 'ALL' }
        },
        {
            IndexName: 'PlayerMatchHistoryIndex',
            KeySchema: [
                { AttributeName: 'player1Id', KeyType: 'HASH' },       // GSI PK
                { AttributeName: 'matchDate', KeyType: 'RANGE' },      // GSI SK attribute 1
                { AttributeName: 'round', KeyType: 'RANGE' }           // GSI SK attribute 2
            ],
            Projection: { ProjectionType: 'ALL' }
        }
    ],
    
    BillingMode: 'PAY_PER_REQUEST'
}));

console.log("Table with multi-attribute GSI keys created successfully");
```

**Keputusan desain utama:**

**Tabel dasar:** Tabel dasar menggunakan kunci `matchId` partisi sederhana untuk pencarian kecocokan langsung, menjaga struktur tabel dasar tetap mudah sementara GSIs menyediakan pola kueri yang kompleks.

**TournamentRegionIndex Indeks Sekunder Global: Indeks** Sekunder `TournamentRegionIndex` Global menggunakan `tournamentId` \$1 `region` sebagai kunci partisi multi-atribut, menciptakan isolasi wilayah turnamen di mana data didistribusikan oleh hash dari kedua atribut yang digabungkan, memungkinkan kueri yang efisien dalam konteks wilayah turnamen tertentu. Kunci pengurutan multi-atribut (`round`\$1 `bracket` \$1`matchId`) menyediakan penyortiran hierarkis yang mendukung kueri di setiap tingkat hierarki dengan urutan alami dari umum (putaran) ke spesifik (ID kecocokan).

**PlayerMatchHistoryIndex Indeks Sekunder Global: Indeks** Sekunder `PlayerMatchHistoryIndex` Global mengatur ulang data berdasarkan pemain menggunakan `player1Id` kunci partisi, memungkinkan kueri lintas-turnamen untuk pemain tertentu. Kunci pengurutan multi-atribut (`matchDate`\$1`round`) menyediakan urutan kronologis dengan kemampuan untuk memfilter berdasarkan rentang tanggal atau putaran turnamen tertentu.

### Langkah 2: Masukkan data dengan atribut asli
<a name="GSI.DesignPattern.MultiAttributeKeys.InsertData"></a>

Tambahkan data pertandingan turnamen menggunakan atribut alami. GSI akan secara otomatis mengindeks atribut ini tanpa memerlukan kunci sintetis.

#### Contoh kode
<a name="w2aac19c13c45c23b9c11b5b5b1"></a>

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, PutCommand } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });
const docClient = DynamoDBDocumentClient.from(client);

// Tournament match data - no synthetic keys needed for GSIs
const matches = [
    // Winter 2024 Tournament, NA-EAST region
    {
        matchId: 'match-001',
        tournamentId: 'WINTER2024',
        region: 'NA-EAST',
        round: 'FINALS',
        bracket: 'CHAMPIONSHIP',
        player1Id: '101',
        player2Id: '103',
        matchDate: '2024-01-20',
        winner: '101',
        score: '3-1'
    },
    {
        matchId: 'match-002',
        tournamentId: 'WINTER2024',
        region: 'NA-EAST',
        round: 'SEMIFINALS',
        bracket: 'UPPER',
        player1Id: '101',
        player2Id: '105',
        matchDate: '2024-01-18',
        winner: '101',
        score: '3-2'
    },
    {
        matchId: 'match-003',
        tournamentId: 'WINTER2024',
        region: 'NA-EAST',
        round: 'SEMIFINALS',
        bracket: 'UPPER',
        player1Id: '103',
        player2Id: '107',
        matchDate: '2024-01-18',
        winner: '103',
        score: '3-0'
    },
    {
        matchId: 'match-004',
        tournamentId: 'WINTER2024',
        region: 'NA-EAST',
        round: 'QUARTERFINALS',
        bracket: 'UPPER',
        player1Id: '101',
        player2Id: '109',
        matchDate: '2024-01-15',
        winner: '101',
        score: '3-1'
    },
    
    // Winter 2024 Tournament, NA-WEST region
    {
        matchId: 'match-005',
        tournamentId: 'WINTER2024',
        region: 'NA-WEST',
        round: 'FINALS',
        bracket: 'CHAMPIONSHIP',
        player1Id: '102',
        player2Id: '104',
        matchDate: '2024-01-20',
        winner: '102',
        score: '3-2'
    },
    {
        matchId: 'match-006',
        tournamentId: 'WINTER2024',
        region: 'NA-WEST',
        round: 'SEMIFINALS',
        bracket: 'UPPER',
        player1Id: '102',
        player2Id: '106',
        matchDate: '2024-01-18',
        winner: '102',
        score: '3-1'
    },
    
    // Spring 2024 Tournament, NA-EAST region
    {
        matchId: 'match-007',
        tournamentId: 'SPRING2024',
        region: 'NA-EAST',
        round: 'QUARTERFINALS',
        bracket: 'UPPER',
        player1Id: '101',
        player2Id: '108',
        matchDate: '2024-03-15',
        winner: '101',
        score: '3-0'
    },
    {
        matchId: 'match-008',
        tournamentId: 'SPRING2024',
        region: 'NA-EAST',
        round: 'QUARTERFINALS',
        bracket: 'LOWER',
        player1Id: '103',
        player2Id: '110',
        matchDate: '2024-03-15',
        winner: '103',
        score: '3-2'
    }
];

// Insert all matches
for (const match of matches) {
    await docClient.send(new PutCommand({
        TableName: 'TournamentMatches',
        Item: match
    }));
    
    console.log(`Added: ${match.matchId} - ${match.tournamentId}/${match.region} - ${match.round} ${match.bracket}`);
}

console.log(`\nInserted ${matches.length} tournament matches`);
console.log("No synthetic keys created - GSIs use native attributes automatically");
```

**Struktur data dijelaskan:**

**Penggunaan atribut alami:** Setiap atribut mewakili konsep turnamen nyata tanpa penggabungan string atau penguraian yang diperlukan, menyediakan pemetaan langsung ke model domain.

**Pengindeksan Indeks Sekunder Global Otomatis:** GSIs Secara otomatis mengindeks item menggunakan atribut yang ada (`tournamentId``region`,,`round`,`bracket`, `matchId` untuk TournamentRegionIndex dan`player1Id`,`matchDate`, `round` untuk PlayerMatchHistoryIndex) tanpa memerlukan kunci gabungan sintetis.

**Tidak perlu pengisian ulang:** Saat Anda menambahkan Indeks Sekunder Global baru dengan kunci multi-atribut ke tabel yang ada, DynamoDB secara otomatis mengindeks semua item yang ada menggunakan atribut alamiahnya—tidak perlu memperbarui item dengan kunci sintetis.

### Langkah 3: Kueri Indeks Sekunder TournamentRegionIndex Global dengan semua atribut kunci partisi
<a name="GSI.DesignPattern.MultiAttributeKeys.QueryAllPartitionKeys"></a>

Contoh ini menanyakan Indeks Sekunder TournamentRegionIndex Global yang memiliki kunci partisi multi-atribut (`tournamentId`\$1`region`). Semua atribut kunci partisi harus ditentukan dengan kondisi kesetaraan dalam kueri—Anda tidak dapat melakukan kueri hanya dengan `tournamentId` sendirian atau menggunakan operator ketidaksetaraan pada atribut kunci partisi.

#### Contoh kode
<a name="w2aac19c13c45c23b9c11b7b5b1"></a>

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });
const docClient = DynamoDBDocumentClient.from(client);

// Query GSI: All matches for WINTER2024 tournament in NA-EAST region
const response = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region',
    ExpressionAttributeNames: {
        '#region': 'region',  // 'region' is a reserved keyword
        '#tournament': 'tournament'
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST'
    }
}));

console.log(`Found ${response.Items.length} matches for WINTER2024/NA-EAST:\n`);
response.Items.forEach(match => {
    console.log(`  ${match.round} | ${match.bracket} | ${match.matchId}`);
    console.log(`    Players: ${match.player1Id} vs ${match.player2Id}`);
    console.log(`    Winner: ${match.winner}, Score: ${match.score}\n`);
});
```

**Output yang diharapkan:**

```
Found 4 matches for WINTER2024/NA-EAST:

  FINALS | CHAMPIONSHIP | match-001
    Players: 101 vs 103
    Winner: 101, Score: 3-1

  QUARTERFINALS | UPPER | match-004
    Players: 101 vs 109
    Winner: 101, Score: 3-1

  SEMIFINALS | UPPER | match-002
    Players: 101 vs 105
    Winner: 101, Score: 3-2

  SEMIFINALS | UPPER | match-003
    Players: 103 vs 107
    Winner: 103, Score: 3-0
```

**Kueri tidak valid:**

```
// Missing region attribute
KeyConditionExpression: 'tournamentId = :tournament'

// Using inequality on partition key attribute
KeyConditionExpression: 'tournamentId = :tournament AND #region > :region'
```

**Kinerja:** Kunci partisi multi-atribut di-hash bersama, memberikan kinerja pencarian O (1) yang sama dengan kunci atribut tunggal.

### Langkah 4: Kueri kunci pengurutan Indeks Sekunder Global left-to-right
<a name="GSI.DesignPattern.MultiAttributeKeys.QuerySortKeysLeftToRight"></a>

Atribut kunci sortir harus ditanyakan left-to-right dalam urutan yang ditentukan dalam Indeks Sekunder Global. Contoh ini menunjukkan kueri TournamentRegionIndex pada tingkat hierarki yang berbeda: memfilter hanya dengan, dengan `round` \$1 `round``bracket`, atau dengan ketiga atribut kunci pengurutan. Anda tidak dapat melewati atribut di tengah—misalnya, Anda tidak dapat melakukan kueri dengan `round` dan `matchId` saat melompati. `bracket`

#### Contoh kode
<a name="w2aac19c13c45c23b9c11b9b5b1"></a>

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });
const docClient = DynamoDBDocumentClient.from(client);

// Query 1: Filter by first sort key attribute (round)
console.log("Query 1: All SEMIFINALS matches");
const query1 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round = :round',
    ExpressionAttributeNames: {
        '#region': 'region'  // 'region' is a reserved keyword
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST',
        ':round': 'SEMIFINALS'
    }
}));
console.log(`  Found ${query1.Items.length} matches\n`);

// Query 2: Filter by first two sort key attributes (round + bracket)
console.log("Query 2: SEMIFINALS UPPER bracket matches");
const query2 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round = :round AND bracket = :bracket',
    ExpressionAttributeNames: {
        '#region': 'region'  // 'region' is a reserved keyword
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST',
        ':round': 'SEMIFINALS',
        ':bracket': 'UPPER'
    }
}));
console.log(`  Found ${query2.Items.length} matches\n`);

// Query 3: Filter by all three sort key attributes (round + bracket + matchId)
console.log("Query 3: Specific match in SEMIFINALS UPPER bracket");
const query3 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round = :round AND bracket = :bracket AND matchId = :matchId',
    ExpressionAttributeNames: {
        '#region': 'region'  // 'region' is a reserved keyword
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST',
        ':round': 'SEMIFINALS',
        ':bracket': 'UPPER',
        ':matchId': 'match-002'
    }
}));
console.log(`  Found ${query3.Items.length} matches\n`);

// Query 4: INVALID - skipping round
console.log("Query 4: Attempting to skip first sort key attribute (WILL FAIL)");
try {
    const query4 = await docClient.send(new QueryCommand({
        TableName: 'TournamentMatches',
        IndexName: 'TournamentRegionIndex',
        KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND bracket = :bracket',
        ExpressionAttributeNames: {
            '#region': 'region'  // 'region' is a reserved keyword
        },
        ExpressionAttributeValues: {
            ':tournament': 'WINTER2024',
            ':region': 'NA-EAST',
            ':bracket': 'UPPER'
        }
    }));
} catch (error) {
    console.log(`  Error: ${error.message}`);
    console.log(`  Cannot skip sort key attributes - must query left-to-right\n`);
}
```

**Output yang diharapkan:**

```
Query 1: All SEMIFINALS matches
  Found 2 matches

Query 2: SEMIFINALS UPPER bracket matches
  Found 2 matches

Query 3: Specific match in SEMIFINALS UPPER bracket
  Found 1 matches

Query 4: Attempting to skip first sort key attribute (WILL FAIL)
  Error: Query key condition not supported
  Cannot skip sort key attributes - must query left-to-right
```

**Left-to-right aturan kueri:** Anda harus menanyakan atribut secara berurutan dari kiri ke kanan, tanpa melewatkan apa pun.

**Pola yang valid:**
+ Atribut pertama saja: `round = 'SEMIFINALS'`
+ Dua atribut pertama: `round = 'SEMIFINALS' AND bracket = 'UPPER'`
+ Ketiga atribut: `round = 'SEMIFINALS' AND bracket = 'UPPER' AND matchId = 'match-002'`

**Pola tidak valid:**
+ Melewatkan atribut pertama: `bracket = 'UPPER'` (melompat-lompat)
+ Menanyakan di luar pesanan: `matchId = 'match-002' AND round = 'SEMIFINALS'`
+ Meninggalkan celah: `round = 'SEMIFINALS' AND matchId = 'match-002'` (melompati braket)

**catatan**  
**Tip desain:** Urutkan atribut kunci urutan dari yang paling umum hingga yang paling spesifik untuk memaksimalkan fleksibilitas kueri.

### Langkah 5: Gunakan kondisi ketidaksetaraan pada kunci pengurutan Indeks Sekunder Global
<a name="GSI.DesignPattern.MultiAttributeKeys.InequalityConditions"></a>

Kondisi ketidaksetaraan harus menjadi kondisi terakhir dalam kueri Anda. Contoh ini menunjukkan menggunakan operator perbandingan (`>=`,`BETWEEN`) dan awalan pencocokan (`begins_with()`) pada atribut kunci sortir. Setelah Anda menggunakan operator ketidaksetaraan, Anda tidak dapat menambahkan kondisi kunci pengurutan tambahan setelahnya — ketidaksetaraan harus menjadi kondisi akhir dalam ekspresi kondisi kunci Anda.

#### Contoh kode
<a name="w2aac19c13c45c23b9c11c11b5b1"></a>

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });
const docClient = DynamoDBDocumentClient.from(client);

// Query 1: Round comparison (inequality on first sort key attribute)
console.log("Query 1: Matches from QUARTERFINALS onwards");
const query1 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round >= :round',
    ExpressionAttributeNames: {
        '#region': 'region'  // 'region' is a reserved keyword
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST',
        ':round': 'QUARTERFINALS'
    }
}));
console.log(`  Found ${query1.Items.length} matches\n`);

// Query 2: Round range with BETWEEN
console.log("Query 2: Matches between QUARTERFINALS and SEMIFINALS");
const query2 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round BETWEEN :start AND :end',
    ExpressionAttributeNames: {
        '#region': 'region'  // 'region' is a reserved keyword
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST',
        ':start': 'QUARTERFINALS',
        ':end': 'SEMIFINALS'
    }
}));
console.log(`  Found ${query2.Items.length} matches\n`);

// Query 3: Prefix matching with begins_with (treated as inequality)
console.log("Query 3: Matches in brackets starting with 'U'");
const query3 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round = :round AND begins_with(bracket, :prefix)',
    ExpressionAttributeNames: {
        '#region': 'region'  // 'region' is a reserved keyword
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST',
        ':round': 'SEMIFINALS',
        ':prefix': 'U'
    }
}));
console.log(`  Found ${query3.Items.length} matches\n`);

// Query 4: INVALID - condition after inequality
console.log("Query 4: Attempting condition after inequality (WILL FAIL)");
try {
    const query4 = await docClient.send(new QueryCommand({
        TableName: 'TournamentMatches',
        IndexName: 'TournamentRegionIndex',
        KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round > :round AND bracket = :bracket',
        ExpressionAttributeNames: {
            '#region': 'region'  // 'region' is a reserved keyword
        },
        ExpressionAttributeValues: {
            ':tournament': 'WINTER2024',
            ':region': 'NA-EAST',
            ':round': 'QUARTERFINALS',
            ':bracket': 'UPPER'
        }
    }));
} catch (error) {
    console.log(`  Error: ${error.message}`);
    console.log(`  Cannot add conditions after inequality - it must be last\n`);
}
```

**Aturan operator ketidaksetaraan:** Anda dapat menggunakan operator perbandingan (`>`,,`>=`,`<=`)`<`, `BETWEEN` untuk kueri rentang, dan `begins_with()` untuk pencocokan awalan. Ketidaksetaraan harus menjadi kondisi terakhir dalam kueri Anda.

**Pola yang valid:**
+ Kondisi kesetaraan diikuti oleh ketidaksetaraan: `round = 'SEMIFINALS' AND bracket = 'UPPER' AND matchId > 'match-001'`
+ Ketimpangan pada atribut pertama: `round BETWEEN 'QUARTERFINALS' AND 'SEMIFINALS'`
+ Pencocokan awalan sebagai kondisi akhir: `round = 'SEMIFINALS' AND begins_with(bracket, 'U')`

**Pola tidak valid:**
+ Menambahkan kondisi setelah ketidaksetaraan: `round > 'QUARTERFINALS' AND bracket = 'UPPER'`
+ Menggunakan beberapa ketidaksetaraan: `round > 'QUARTERFINALS' AND bracket > 'L'`

**penting**  
`begins_with()`diperlakukan sebagai kondisi ketidaksetaraan, jadi tidak ada kondisi kunci pengurutan tambahan yang dapat mengikutinya.

### Langkah 6: Kueri Indeks Sekunder PlayerMatchHistoryIndex Global dengan kunci pengurutan multi-atribut
<a name="GSI.DesignPattern.MultiAttributeKeys.QueryPlayerHistory"></a>

Contoh ini menanyakan PlayerMatchHistoryIndex yang memiliki kunci partisi tunggal (`player1Id`) dan kunci sortir multi-atribut (`matchDate`\$1`round`). Hal ini memungkinkan analisis lintas-turnamen dengan menanyakan semua pertandingan untuk pemain tertentu tanpa mengetahui turnamen IDs — sedangkan tabel dasar akan membutuhkan kueri terpisah per kombinasi turnamen-wilayah.

#### Contoh kode
<a name="w2aac19c13c45c23b9c11c13b5b1"></a>

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });
const docClient = DynamoDBDocumentClient.from(client);

// Query 1: All matches for Player 101 across all tournaments
console.log("Query 1: All matches for Player 101");
const query1 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'PlayerMatchHistoryIndex',
    KeyConditionExpression: 'player1Id = :player',
    ExpressionAttributeValues: {
        ':player': '101'
    }
}));

console.log(`  Found ${query1.Items.length} matches for Player 101:`);
query1.Items.forEach(match => {
    console.log(`    ${match.tournamentId}/${match.region} - ${match.matchDate} - ${match.round}`);
});
console.log();

// Query 2: Player 101 matches on specific date
console.log("Query 2: Player 101 matches on 2024-01-18");
const query2 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'PlayerMatchHistoryIndex',
    KeyConditionExpression: 'player1Id = :player AND matchDate = :date',
    ExpressionAttributeValues: {
        ':player': '101',
        ':date': '2024-01-18'
    }
}));

console.log(`  Found ${query2.Items.length} matches\n`);

// Query 3: Player 101 SEMIFINALS matches on specific date
console.log("Query 3: Player 101 SEMIFINALS matches on 2024-01-18");
const query3 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'PlayerMatchHistoryIndex',
    KeyConditionExpression: 'player1Id = :player AND matchDate = :date AND round = :round',
    ExpressionAttributeValues: {
        ':player': '101',
        ':date': '2024-01-18',
        ':round': 'SEMIFINALS'
    }
}));

console.log(`  Found ${query3.Items.length} matches\n`);

// Query 4: Player 101 matches in date range
console.log("Query 4: Player 101 matches in January 2024");
const query4 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'PlayerMatchHistoryIndex',
    KeyConditionExpression: 'player1Id = :player AND matchDate BETWEEN :start AND :end',
    ExpressionAttributeValues: {
        ':player': '101',
        ':start': '2024-01-01',
        ':end': '2024-01-31'
    }
}));

console.log(`  Found ${query4.Items.length} matches\n`);
```

## Variasi pola
<a name="GSI.DesignPattern.MultiAttributeKeys.PatternVariations"></a>

### Data deret waktu dengan kunci multi-atribut
<a name="GSI.DesignPattern.MultiAttributeKeys.TimeSeries"></a>

Optimalkan kueri deret waktu dengan atribut waktu hierarkis

#### Contoh kode
<a name="w2aac19c13c45c23b9c13b3b5b1"></a>

```
{
    TableName: 'IoTReadings',
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'readingId', KeyType: 'HASH' }
    ],
    AttributeDefinitions: [
        { AttributeName: 'readingId', AttributeType: 'S' },
        { AttributeName: 'deviceId', AttributeType: 'S' },
        { AttributeName: 'locationId', AttributeType: 'S' },
        { AttributeName: 'year', AttributeType: 'S' },
        { AttributeName: 'month', AttributeType: 'S' },
        { AttributeName: 'day', AttributeType: 'S' },
        { AttributeName: 'timestamp', AttributeType: 'S' }
    ],
    // GSI with multi-attribute keys for time-series queries
    GlobalSecondaryIndexes: [{
        IndexName: 'DeviceLocationTimeIndex',
        KeySchema: [
            { AttributeName: 'deviceId', KeyType: 'HASH' },
            { AttributeName: 'locationId', KeyType: 'HASH' },
            { AttributeName: 'year', KeyType: 'RANGE' },
            { AttributeName: 'month', KeyType: 'RANGE' },
            { AttributeName: 'day', KeyType: 'RANGE' },
            { AttributeName: 'timestamp', KeyType: 'RANGE' }
        ],
        Projection: { ProjectionType: 'ALL' }
    }],
    BillingMode: 'PAY_PER_REQUEST'
}

// Query patterns enabled via GSI:
// - All readings for device in location
// - Readings for specific year
// - Readings for specific month in year
// - Readings for specific day
// - Readings in time range
```

**Manfaat:** Hirarki waktu alami (tahun → bulan → hari → stempel waktu) memungkinkan kueri yang efisien setiap saat perincian tanpa penguraian atau manipulasi tanggal. Global Secondary Index secara otomatis mengindeks semua bacaan menggunakan atribut waktu alaminya.

### Pesanan e-niaga dengan kunci multi-atribut
<a name="GSI.DesignPattern.MultiAttributeKeys.ECommerce"></a>

Lacak pesanan dengan berbagai dimensi

#### Contoh kode
<a name="w2aac19c13c45c23b9c13b5b5b1"></a>

```
{
    TableName: 'Orders',
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'orderId', KeyType: 'HASH' }
    ],
    AttributeDefinitions: [
        { AttributeName: 'orderId', AttributeType: 'S' },
        { AttributeName: 'sellerId', AttributeType: 'S' },
        { AttributeName: 'region', AttributeType: 'S' },
        { AttributeName: 'orderDate', AttributeType: 'S' },
        { AttributeName: 'category', AttributeType: 'S' },
        { AttributeName: 'customerId', AttributeType: 'S' },
        { AttributeName: 'orderStatus', AttributeType: 'S' }
    ],
    GlobalSecondaryIndexes: [
        {
            IndexName: 'SellerRegionIndex',
            KeySchema: [
                { AttributeName: 'sellerId', KeyType: 'HASH' },
                { AttributeName: 'region', KeyType: 'HASH' },
                { AttributeName: 'orderDate', KeyType: 'RANGE' },
                { AttributeName: 'category', KeyType: 'RANGE' },
                { AttributeName: 'orderId', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'ALL' }
        },
        {
            IndexName: 'CustomerOrdersIndex',
            KeySchema: [
                { AttributeName: 'customerId', KeyType: 'HASH' },
                { AttributeName: 'orderDate', KeyType: 'RANGE' },
                { AttributeName: 'orderStatus', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'ALL' }
        }
    ],
    BillingMode: 'PAY_PER_REQUEST'
}

// SellerRegionIndex GSI queries:
// - Orders by seller and region
// - Orders by seller, region, and date
// - Orders by seller, region, date, and category

// CustomerOrdersIndex GSI queries:
// - Customer's orders
// - Customer's orders by date
// - Customer's orders by date and status
```

### Data organisasi hierarkis
<a name="GSI.DesignPattern.MultiAttributeKeys.Hierarchical"></a>

Model hierarki organisasi

#### Contoh kode
<a name="w2aac19c13c45c23b9c13b7b5b1"></a>

```
{
    TableName: 'Employees',
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'employeeId', KeyType: 'HASH' }
    ],
    AttributeDefinitions: [
        { AttributeName: 'employeeId', AttributeType: 'S' },
        { AttributeName: 'companyId', AttributeType: 'S' },
        { AttributeName: 'divisionId', AttributeType: 'S' },
        { AttributeName: 'departmentId', AttributeType: 'S' },
        { AttributeName: 'teamId', AttributeType: 'S' },
        { AttributeName: 'skillCategory', AttributeType: 'S' },
        { AttributeName: 'skillLevel', AttributeType: 'S' },
        { AttributeName: 'yearsExperience', AttributeType: 'N' }
    ],
    GlobalSecondaryIndexes: [
        {
            IndexName: 'OrganizationIndex',
            KeySchema: [
                { AttributeName: 'companyId', KeyType: 'HASH' },
                { AttributeName: 'divisionId', KeyType: 'HASH' },
                { AttributeName: 'departmentId', KeyType: 'RANGE' },
                { AttributeName: 'teamId', KeyType: 'RANGE' },
                { AttributeName: 'employeeId', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'ALL' }
        },
        {
            IndexName: 'SkillsIndex',
            KeySchema: [
                { AttributeName: 'skillCategory', KeyType: 'HASH' },
                { AttributeName: 'skillLevel', KeyType: 'RANGE' },
                { AttributeName: 'yearsExperience', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'INCLUDE', NonKeyAttributes: ['employeeId', 'name'] }
        }
    ],
    BillingMode: 'PAY_PER_REQUEST'
}

// OrganizationIndex GSI query patterns:
// - All employees in company/division
// - Employees in specific department
// - Employees in specific team

// SkillsIndex GSI query patterns:
// - Employees by skill and experience level
```

### Kunci multi-atribut jarang
<a name="GSI.DesignPattern.MultiAttributeKeys.Sparse"></a>

Gabungkan kunci multi-atribut untuk membuat GSI yang jarang

#### Contoh kode
<a name="w2aac19c13c45c23b9c13b9b5b1"></a>

```
{
    TableName: 'Products',
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'productId', KeyType: 'HASH' }
    ],
    AttributeDefinitions: [
        { AttributeName: 'productId', AttributeType: 'S' },
        { AttributeName: 'categoryId', AttributeType: 'S' },
        { AttributeName: 'subcategoryId', AttributeType: 'S' },
        { AttributeName: 'averageRating', AttributeType: 'N' },
        { AttributeName: 'reviewCount', AttributeType: 'N' }
    ],
    GlobalSecondaryIndexes: [
        {
            IndexName: 'CategoryIndex',
            KeySchema: [
                { AttributeName: 'categoryId', KeyType: 'HASH' },
                { AttributeName: 'subcategoryId', KeyType: 'HASH' },
                { AttributeName: 'productId', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'ALL' }
        },
        {
            IndexName: 'ReviewedProductsIndex',
            KeySchema: [
                { AttributeName: 'categoryId', KeyType: 'HASH' },
                { AttributeName: 'averageRating', KeyType: 'RANGE' },  // Optional attribute
                { AttributeName: 'reviewCount', KeyType: 'RANGE' }     // Optional attribute
            ],
            Projection: { ProjectionType: 'ALL' }
        }
    ],
    BillingMode: 'PAY_PER_REQUEST'
}

// Only products with reviews appear in ReviewedProductsIndex GSI
// Automatic filtering without application logic
// Multi-attribute sort key enables rating and count queries
```

### SaaS multi-tenancy
<a name="GSI.DesignPattern.MultiAttributeKeys.SaaS"></a>

Platform SaaS multi-penyewa dengan isolasi pelanggan

#### Contoh kode
<a name="w2aac19c13c45c23b9c13c11b5b1"></a>

```
// Table design
{
    TableName: 'SaasData',
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'resourceId', KeyType: 'HASH' }
    ],
    AttributeDefinitions: [
        { AttributeName: 'resourceId', AttributeType: 'S' },
        { AttributeName: 'tenantId', AttributeType: 'S' },
        { AttributeName: 'customerId', AttributeType: 'S' },
        { AttributeName: 'resourceType', AttributeType: 'S' }
    ],
    // GSI with multi-attribute keys for tenant-customer isolation
    GlobalSecondaryIndexes: [{
        IndexName: 'TenantCustomerIndex',
        KeySchema: [
            { AttributeName: 'tenantId', KeyType: 'HASH' },
            { AttributeName: 'customerId', KeyType: 'HASH' },
            { AttributeName: 'resourceType', KeyType: 'RANGE' },
            { AttributeName: 'resourceId', KeyType: 'RANGE' }
        ],
        Projection: { ProjectionType: 'ALL' }
    }],
    BillingMode: 'PAY_PER_REQUEST'
}

// Query GSI: All resources for tenant T001, customer C001
const resources = await docClient.send(new QueryCommand({
    TableName: 'SaasData',
    IndexName: 'TenantCustomerIndex',
    KeyConditionExpression: 'tenantId = :tenant AND customerId = :customer',
    ExpressionAttributeValues: {
        ':tenant': 'T001',
        ':customer': 'C001'
    }
}));

// Query GSI: Specific resource type for tenant/customer
const documents = await docClient.send(new QueryCommand({
    TableName: 'SaasData',
    IndexName: 'TenantCustomerIndex',
    KeyConditionExpression: 'tenantId = :tenant AND customerId = :customer AND resourceType = :type',
    ExpressionAttributeValues: {
        ':tenant': 'T001',
        ':customer': 'C001',
        ':type': 'document'
    }
}));
```

**Manfaat:** Kueri yang efisien dalam konteks penyewa-pelanggan dan organisasi data alami.

### Transaksi keuangan
<a name="GSI.DesignPattern.MultiAttributeKeys.Financial"></a>

Sistem perbankan melacak transaksi rekening menggunakan GSIs

#### Contoh kode
<a name="w2aac19c13c45c23b9c13c13b5b1"></a>

```
// Table design
{
    TableName: 'BankTransactions',
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'transactionId', KeyType: 'HASH' }
    ],
    AttributeDefinitions: [
        { AttributeName: 'transactionId', AttributeType: 'S' },
        { AttributeName: 'accountId', AttributeType: 'S' },
        { AttributeName: 'year', AttributeType: 'S' },
        { AttributeName: 'month', AttributeType: 'S' },
        { AttributeName: 'day', AttributeType: 'S' },
        { AttributeName: 'transactionType', AttributeType: 'S' }
    ],
    GlobalSecondaryIndexes: [
        {
            IndexName: 'AccountTimeIndex',
            KeySchema: [
                { AttributeName: 'accountId', KeyType: 'HASH' },
                { AttributeName: 'year', KeyType: 'RANGE' },
                { AttributeName: 'month', KeyType: 'RANGE' },
                { AttributeName: 'day', KeyType: 'RANGE' },
                { AttributeName: 'transactionId', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'ALL' }
        },
        {
            IndexName: 'TransactionTypeIndex',
            KeySchema: [
                { AttributeName: 'accountId', KeyType: 'HASH' },
                { AttributeName: 'transactionType', KeyType: 'RANGE' },
                { AttributeName: 'year', KeyType: 'RANGE' },
                { AttributeName: 'month', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'ALL' }
        }
    ],
    BillingMode: 'PAY_PER_REQUEST'
}

// Query AccountTimeIndex GSI: All transactions for account in 2023
const yearTransactions = await docClient.send(new QueryCommand({
    TableName: 'BankTransactions',
    IndexName: 'AccountTimeIndex',
    KeyConditionExpression: 'accountId = :account AND #year = :year',
    ExpressionAttributeNames: { '#year': 'year' },
    ExpressionAttributeValues: {
        ':account': 'ACC-12345',
        ':year': '2023'
    }
}));

// Query AccountTimeIndex GSI: Transactions in specific month
const monthTransactions = await docClient.send(new QueryCommand({
    TableName: 'BankTransactions',
    IndexName: 'AccountTimeIndex',
    KeyConditionExpression: 'accountId = :account AND #year = :year AND #month = :month',
    ExpressionAttributeNames: { '#year': 'year', '#month': 'month' },
    ExpressionAttributeValues: {
        ':account': 'ACC-12345',
        ':year': '2023',
        ':month': '11'
    }
}));

// Query TransactionTypeIndex GSI: Deposits in 2023
const deposits = await docClient.send(new QueryCommand({
    TableName: 'BankTransactions',
    IndexName: 'TransactionTypeIndex',
    KeyConditionExpression: 'accountId = :account AND transactionType = :type AND #year = :year',
    ExpressionAttributeNames: { '#year': 'year' },
    ExpressionAttributeValues: {
        ':account': 'ACC-12345',
        ':type': 'deposit',
        ':year': '2023'
    }
}));
```

## Contoh lengkap
<a name="GSI.DesignPattern.MultiAttributeKeys.CompleteExample"></a>

Contoh berikut menunjukkan kunci multi-atribut dari penyiapan ke pembersihan:

### Contoh kode
<a name="w2aac19c13c45c23b9c15b5b1"></a>

```
import { 
    DynamoDBClient, 
    CreateTableCommand, 
    DeleteTableCommand, 
    waitUntilTableExists 
} from "@aws-sdk/client-dynamodb";
import { 
    DynamoDBDocumentClient, 
    PutCommand, 
    QueryCommand 
} from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });
const docClient = DynamoDBDocumentClient.from(client);

async function multiAttributeKeysDemo() {
    console.log("Starting Multi-Attribute GSI Keys Demo\n");
    
    // Step 1: Create table with GSIs using multi-attribute keys
    console.log("1. Creating table with multi-attribute GSI keys...");
    await client.send(new CreateTableCommand({
        TableName: 'TournamentMatches',
        KeySchema: [
            { AttributeName: 'matchId', KeyType: 'HASH' }
        ],
        AttributeDefinitions: [
            { AttributeName: 'matchId', AttributeType: 'S' },
            { AttributeName: 'tournamentId', AttributeType: 'S' },
            { AttributeName: 'region', AttributeType: 'S' },
            { AttributeName: 'round', AttributeType: 'S' },
            { AttributeName: 'bracket', AttributeType: 'S' },
            { AttributeName: 'player1Id', AttributeType: 'S' },
            { AttributeName: 'matchDate', AttributeType: 'S' }
        ],
        GlobalSecondaryIndexes: [
            {
                IndexName: 'TournamentRegionIndex',
                KeySchema: [
                    { AttributeName: 'tournamentId', KeyType: 'HASH' },
                    { AttributeName: 'region', KeyType: 'HASH' },
                    { AttributeName: 'round', KeyType: 'RANGE' },
                    { AttributeName: 'bracket', KeyType: 'RANGE' },
                    { AttributeName: 'matchId', KeyType: 'RANGE' }
                ],
                Projection: { ProjectionType: 'ALL' }
            },
            {
                IndexName: 'PlayerMatchHistoryIndex',
                KeySchema: [
                    { AttributeName: 'player1Id', KeyType: 'HASH' },
                    { AttributeName: 'matchDate', KeyType: 'RANGE' },
                    { AttributeName: 'round', KeyType: 'RANGE' }
                ],
                Projection: { ProjectionType: 'ALL' }
            }
        ],
        BillingMode: 'PAY_PER_REQUEST'
    }));
    
    await waitUntilTableExists({ client, maxWaitTime: 120 }, { TableName: 'TournamentMatches' });
    console.log("Table created\n");
    
    // Step 2: Insert tournament matches
    console.log("2. Inserting tournament matches...");
    const matches = [
        { matchId: 'match-001', tournamentId: 'WINTER2024', region: 'NA-EAST', round: 'FINALS', bracket: 'CHAMPIONSHIP', player1Id: '101', player2Id: '103', matchDate: '2024-01-20', winner: '101', score: '3-1' },
        { matchId: 'match-002', tournamentId: 'WINTER2024', region: 'NA-EAST', round: 'SEMIFINALS', bracket: 'UPPER', player1Id: '101', player2Id: '105', matchDate: '2024-01-18', winner: '101', score: '3-2' },
        { matchId: 'match-003', tournamentId: 'WINTER2024', region: 'NA-WEST', round: 'FINALS', bracket: 'CHAMPIONSHIP', player1Id: '102', player2Id: '104', matchDate: '2024-01-20', winner: '102', score: '3-2' },
        { matchId: 'match-004', tournamentId: 'SPRING2024', region: 'NA-EAST', round: 'QUARTERFINALS', bracket: 'UPPER', player1Id: '101', player2Id: '108', matchDate: '2024-03-15', winner: '101', score: '3-0' }
    ];
    
    for (const match of matches) {
        await docClient.send(new PutCommand({ TableName: 'TournamentMatches', Item: match }));
    }
    console.log(`Inserted ${matches.length} tournament matches\n`);
    
    // Step 3: Query GSI with multi-attribute partition key
    console.log("3. Query TournamentRegionIndex GSI: WINTER2024/NA-EAST matches");
    const gsiQuery1 = await docClient.send(new QueryCommand({
        TableName: 'TournamentMatches',
        IndexName: 'TournamentRegionIndex',
        KeyConditionExpression: 'tournamentId = :tournament AND #region = :region',
        ExpressionAttributeNames: { '#region': 'region' },
        ExpressionAttributeValues: { ':tournament': 'WINTER2024', ':region': 'NA-EAST' }
    }));
    
    console.log(`  Found ${gsiQuery1.Items.length} matches:`);
    gsiQuery1.Items.forEach(match => {
        console.log(`    ${match.round} - ${match.bracket} - ${match.winner} won`);
    });
    
    // Step 4: Query GSI with multi-attribute sort key
    console.log("\n4. Query PlayerMatchHistoryIndex GSI: All matches for Player 101");
    const gsiQuery2 = await docClient.send(new QueryCommand({
        TableName: 'TournamentMatches',
        IndexName: 'PlayerMatchHistoryIndex',
        KeyConditionExpression: 'player1Id = :player',
        ExpressionAttributeValues: { ':player': '101' }
    }));
    
    console.log(`  Found ${gsiQuery2.Items.length} matches for Player 101:`);
    gsiQuery2.Items.forEach(match => {
        console.log(`    ${match.tournamentId}/${match.region} - ${match.matchDate} - ${match.round}`);
    });
    
    console.log("\nDemo complete");
    console.log("No synthetic keys needed - GSIs use native attributes automatically");
}

async function cleanup() {
    console.log("Deleting table...");
    await client.send(new DeleteTableCommand({ TableName: 'TournamentMatches' }));
    console.log("Table deleted");
}

// Run demo
multiAttributeKeysDemo().catch(console.error);

// Uncomment to cleanup:
// cleanup().catch(console.error);
```

**Perancah kode minimal**

### Contoh kode
<a name="w2aac19c13c45c23b9c15b9b1"></a>

```
// 1. Create table with GSI using multi-attribute keys
await client.send(new CreateTableCommand({
    TableName: 'MyTable',
    KeySchema: [
        { AttributeName: 'id', KeyType: 'HASH' }        // Simple base table PK
    ],
    AttributeDefinitions: [
        { AttributeName: 'id', AttributeType: 'S' },
        { AttributeName: 'attr1', AttributeType: 'S' },
        { AttributeName: 'attr2', AttributeType: 'S' },
        { AttributeName: 'attr3', AttributeType: 'S' },
        { AttributeName: 'attr4', AttributeType: 'S' }
    ],
    GlobalSecondaryIndexes: [{
        IndexName: 'MyGSI',
        KeySchema: [
            { AttributeName: 'attr1', KeyType: 'HASH' },    // GSI PK attribute 1
            { AttributeName: 'attr2', KeyType: 'HASH' },    // GSI PK attribute 2
            { AttributeName: 'attr3', KeyType: 'RANGE' },   // GSI SK attribute 1
            { AttributeName: 'attr4', KeyType: 'RANGE' }    // GSI SK attribute 2
        ],
        Projection: { ProjectionType: 'ALL' }
    }],
    BillingMode: 'PAY_PER_REQUEST'
}));

// 2. Insert items with native attributes (no concatenation needed for GSI)
await docClient.send(new PutCommand({
    TableName: 'MyTable',
    Item: {
        id: 'item-001',
        attr1: 'value1',
        attr2: 'value2',
        attr3: 'value3',
        attr4: 'value4',
        // ... other attributes
    }
}));

// 3. Query GSI with all partition key attributes
await docClient.send(new QueryCommand({
    TableName: 'MyTable',
    IndexName: 'MyGSI',
    KeyConditionExpression: 'attr1 = :v1 AND attr2 = :v2',
    ExpressionAttributeValues: {
        ':v1': 'value1',
        ':v2': 'value2'
    }
}));

// 4. Query GSI with sort key attributes (left-to-right)
await docClient.send(new QueryCommand({
    TableName: 'MyTable',
    IndexName: 'MyGSI',
    KeyConditionExpression: 'attr1 = :v1 AND attr2 = :v2 AND attr3 = :v3',
    ExpressionAttributeValues: {
        ':v1': 'value1',
        ':v2': 'value2',
        ':v3': 'value3'
    }
}));

// Note: If any attribute name is a DynamoDB reserved keyword, use ExpressionAttributeNames:
// KeyConditionExpression: 'attr1 = :v1 AND #attr2 = :v2'
// ExpressionAttributeNames: { '#attr2': 'attr2' }
```

## Sumber daya tambahan
<a name="GSI.DesignPattern.MultiAttributeKeys.AdditionalResources"></a>
+ [Praktik Terbaik DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/best-practices.html)
+ [Bekerja dengan Tabel dan Data](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithTables.html)
+ [Indeks Sekunder Global](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html)
+ [Operasi Kueri dan Pemindaian](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html)

# Mengelola Indeks Sekunder Global di DynamoDB
<a name="GSI.OnlineOps"></a>

Bagian ini menjelaskan cara membuat, mengubah, dan menghapus indeks sekunder global di Amazon DynamoDB.

**Topics**
+ [Membuat tabel dengan Indeks Sekunder Global](#GSI.Creating)
+ [Mendeskripsikan Indeks Sekunder Global pada tabel](#GSI.Describing)
+ [Menambahkan Indeks Sekunder Global ke tabel yang sudah ada](#GSI.OnlineOps.Creating)
+ [Menghapus Indeks Sekunder Global](#GSI.OnlineOps.Deleting)
+ [Mengubah Indeks Sekunder Global selama pembuatan](#GSI.OnlineOps.Creating.Modify)

## Membuat tabel dengan Indeks Sekunder Global
<a name="GSI.Creating"></a>

Untuk membuat tabel dengan satu atau beberapa indeks sekunder global, gunakan operasi `CreateTable` dengan parameter `GlobalSecondaryIndexes`. Untuk fleksibilitas kueri maksimum, Anda dapat membuat hingga 20 indeks sekunder global (kuota default) per tabel. 

Anda harus menentukan satu atribut untuk bertindak sebagai kunci partisi indeks. Anda dapat secara opsional menentukan atribut lain untuk kunci urutan indeks. Atribut kunci ini tidak perlu sama dengan atribut kunci dalam tabel. Misalnya, dalam *GameScores*tabel (lihat[Menggunakan Indeks Sekunder Global di DynamoDB](GSI.md)), tidak `TopScore` `TopScoreDateTime` juga atribut kunci. Anda dapat membuat indeks sekunder global dengan kunci partisi `TopScore` dan kunci urutan `TopScoreDateTime`. Anda dapat menggunakan indeks semacam itu untuk menentukan apakah ada korelasi antara skor tinggi dan waktu game dimainkan.

Setiap atribut kunci indeks harus berupa skalar berjenis `String`, `Number`, atau `Binary`. (Tidak boleh berupa dokumen atau kumpulan.) Anda dapat memproyeksikan atribut jenis data apa pun ke dalam indeks sekunder global. Ini termasuk skalar, dokumen, dan kumpulan. Untuk daftar lengkap jenis data, lihat [Jenis Data](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes).

Jika menggunakan mode yang disediakan, Anda harus menyediakan pengaturan `ProvisionedThroughput` untuk indeks, yang terdiri dari `ReadCapacityUnits` dan `WriteCapacityUnits`. Pengaturan throughput yang disediakan ini terpisah dari pengaturan tabel, tetapi berperilaku dengan cara yang serupa. Untuk informasi selengkapnya, lihat [Pertimbangan Throughput yang disediakan untuk Indeks Sekunder Global](GSI.md#GSI.ThroughputConsiderations).

 Indeks sekunder global mewarisi mode read/write kapasitas dari tabel dasar. Untuk informasi selengkapnya, lihat [Pertimbangan saat mengganti mode kapasitas di DynamoDB](bp-switching-capacity-modes.md). 

**catatan**  
 Saat membuat GSI baru, penting untuk memeriksa apakah pilihan kunci partisi Anda menghasilkan distribusi data atau lalu lintas yang tidak merata atau menyempit di seluruh nilai kunci partisi indeks baru. Jika ini terjadi, Anda mungkin melihat operasi backfill dan tulis terjadi secara bersamaan dan membatasi penulisan ke tabel dasar. Layanan mengambil tindakan untuk meminimalkan potensi skenario ini, tetapi tidak memiliki wawasan tentang bentuk data pelanggan sehubungan dengan kunci partisi indeks, proyeksi yang dipilih, atau ketersebaran kunci primer indeks.  
Jika Anda mencurigai bahwa indeks sekunder global Anda yang baru mungkin memiliki data atau distribusi lalu lintas yang sempit atau tidak merata di seluruh nilai kunci partisi, pertimbangkan hal berikut sebelum menambahkan indeks baru ke tabel yang penting secara operasional.  
Mungkin yang paling aman adalah menambahkan indeks pada saat aplikasi Anda menghasilkan jumlah lalu lintas paling sedikit.
Pertimbangkan untuk mengaktifkan CloudWatch Contributor Insights pada tabel dasar dan indeks Anda. Ini akan memberi Anda wawasan berharga mengenai distribusi lalu lintas Anda.
 Tonton`WriteThrottleEvents`,`ThrottledRequests`, dan `OnlineIndexPercentageProgress` CloudWatch metrik selama proses berlangsung. Sesuaikan kapasitas penulisan yang disediakan sesuai kebutuhan untuk menyelesaikan pengisian ulang dalam waktu yang wajar tanpa efek pelambatan yang signifikan pada operasi Anda yang sedang berlangsung. `OnlineIndexConsumedWriteCapacity`dan `OnlineThrottleEvents` diharapkan menunjukkan 0 selama pengurukan indeks.
Bersiaplah untuk membatalkan pembuatan indeks jika Anda mengalami dampak operasional karena pembatasan penulisan.

## Mendeskripsikan Indeks Sekunder Global pada tabel
<a name="GSI.Describing"></a>

Untuk melihat status semua indeks sekunder global pada tabel, gunakan operasi `DescribeTable`. Bagian `GlobalSecondaryIndexes` dari respons menunjukkan semua indeks pada tabel, beserta status masing-masing indeks saat ini ( `IndexStatus`).

`IndexStatus` untuk indeks sekunder global akan menjadi salah satu dari berikut ini:
+ `CREATING` — Indeks sedang dibuat, dan belum tersedia untuk digunakan.
+ `ACTIVE` — Indeks siap digunakan, dan aplikasi dapat melakukan operasi `Query` pada indeks.
+ `UPDATING` — Pengaturan throughput indeks yang tersedia sedang diubah.
+ `DELETING` — Indeks saat ini sedang dihapus, dan tidak dapat lagi digunakan.

Setelah DynamoDB selesai membuat indeks sekunder global, status indeks berubah dari `CREATING` menjadi `ACTIVE`.

## Menambahkan Indeks Sekunder Global ke tabel yang sudah ada
<a name="GSI.OnlineOps.Creating"></a>

Untuk menambahkan indeks sekunder global ke tabel yang sudah ada, gunakan operasi `UpdateTable` dengan parameter `GlobalSecondaryIndexUpdates`. Anda harus memasukkan berikut ini:
+ Nama indeks. Nama harus berbeda dari semua indeks pada tabel.
+ Skema kunci indeks. Anda harus menentukan satu atribut untuk kunci partisi indeks; Anda dapat secara opsional menentukan atribut lain untuk kunci urutan indeks. Atribut kunci ini tidak perlu sama dengan atribut kunci dalam tabel. Jenis data untuk setiap atribut skema harus skalar: `String`, `Number`, atau `Binary`.
+ Atribut yang akan diproyeksikan dari tabel ke dalam indeks:
  + `KEYS_ONLY` — Setiap item dalam indeks hanya terdiri dari kunci partisi tabel dan nilai kunci urutan, ditambah nilai kunci indeks. 
  + `INCLUDE` — Selain atribut yang dijelaskan dalam `KEYS_ONLY`, indeks sekunder menyertakan atribut non-kunci lain yang Anda tentukan.
  + `ALL` — Indeks menyertakan semua atribut dari tabel sumber.
+ Setelan throughput yang disediakan untuk indeks, yang terdiri dari `ReadCapacityUnits` dan `WriteCapacityUnits`. Pengaturan throughput yang disediakan ini terpisah dari pengaturan tabel.

Anda hanya dapat membuat satu indeks sekunder global per operasi `UpdateTable`.

### Fase pembuatan indeks
<a name="GSI.OnlineOps.Creating.Phases"></a>

Saat Anda menambahkan indeks sekunder global baru ke tabel yang sudah ada, tabel akan terus tersedia meskipun indeks sedang dibuat. Namun, indeks baru tidak tersedia untuk operasi Kueri hingga statusnya berubah dari `CREATING` menjadi `ACTIVE`.

**catatan**  
Pembuatan indeks sekunder global tidak menggunakan Application Auto Scaling. Meningkatkan kapasitas Application Auto Scaling `MIN` tidak akan mengurangi waktu pembuatan indeks sekunder global.

Di balik layar, DynamoDB membuat indeks dalam dua fase:

**Alokasi Sumber Daya**  
DynamoDB mengalokasikan sumber daya komputasi dan penyimpanan yang diperlukan untuk membuat indeks.  
Selama fase alokasi sumber daya, atribut `IndexStatus` adalah `CREATING` dan atribut `Backfilling` adalah false. Gunakan operasi `DescribeTable` untuk mengambil status tabel dan semua indeks sekundernya.  
Saat indeks berada dalam fase alokasi sumber daya, Anda tidak dapat menghapus indeks atau menghapus tabel induknya. Anda juga tidak dapat mengubah throughput indeks atau tabel yang disediakan. Anda tidak dapat menambahkan atau menghapus indeks lain pada tabel. Namun, Anda dapat mengubah throughput yang disediakan dari indeks lain tersebut.

**Backfill**  
Untuk setiap item dalam tabel, DynamoDB menentukan kumpulan atribut yang akan ditulis ke indeks berdasarkan proyeksinya (`KEYS_ONLY`, `INCLUDE`, atau `ALL`). Kemudian atribut ini ditulis ke indeks. Selama fase backfill, DynamoDB melacak item yang ditambahkan, dihapus, atau diperbarui dalam tabel. Atribut dari item ini juga ditambahkan, dihapus, atau diperbarui dalam indeks yang sesuai.  
Selama fase backfill, atribut `IndexStatus` diatur ke `CREATING`, dan atribut `Backfilling` adalah true. Gunakan operasi `DescribeTable` untuk mengambil status tabel dan semua indeks sekundernya.  
Saat indeks sedang melakukan backfill, Anda tidak dapat menghapus tabel induknya. Namun, Anda masih dapat menghapus indeks atau mengubah throughput tabel yang disediakan dan indeks sekunder globalnya.  
Selama fase backfill, beberapa penulisan item yang melanggar mungkin berhasil, sementara yang lain ditolak. Setelah backfill, semua penulisan ke item yang melanggar skema kunci indeks baru akan ditolak. Sebaiknya Anda menjalankan alat Detektor Pelanggaran setelah fase backfill selesai untuk mendeteksi dan mengatasi pelanggaran utama yang mungkin terjadi. Untuk informasi selengkapnya, lihat [Mendeteksi dan memperbaiki pelanggaran kunci indeks di DynamoDB](GSI.OnlineOps.ViolationDetection.md).

Saat fase alokasi sumber daya dan backfill sedang berlangsung, indeks berada dalam status `CREATING`. Selama waktu ini, DynamoDB melakukan operasi baca pada tabel. Operasi baca dari tabel dasar untuk mengisi indeks sekunder global tidak dikenakan biaya.

Setelah pembuatan indeks selesai, statusnya berubah menjadi `ACTIVE`. Anda tidak dapat `Query` atau `Scan` indeks sampai indeks itu `ACTIVE`.

**catatan**  
Dalam beberapa kasus, DynamoDB tidak dapat menulis data dari tabel ke indeks karena pelanggaran kunci indeks. Hal ini dapat terjadi jika:  
Jenis data nilai atribut tidak cocok dengan jenis data skema kunci indeks.
Ukuran atribut melebihi panjang maksimum atribut kunci indeks.
Atribut kunci indeks memiliki String kosong atau nilai atribut Binari kosong.
Pelanggaran kunci indeks tidak mengganggu pembuatan indeks sekunder global. Namun, ketika indeks menjadi `ACTIVE`, kunci yang melanggar tidak ada dalam indeks.  
DynamoDB menyediakan alat mandiri untuk menemukan dan menyelesaikan masalah ini. Untuk informasi selengkapnya, lihat [Mendeteksi dan memperbaiki pelanggaran kunci indeks di DynamoDB](GSI.OnlineOps.ViolationDetection.md).

### Menambahkan Indeks Sekunder Global ke tabel besar
<a name="GSI.OnlineOps.Creating.LargeTable"></a>

Waktu yang dibutuhkan untuk membuat indeks sekunder global tergantung beberapa faktor, seperti berikut ini:
+ Ukuran ruang tabel
+ Jumlah item dalam tabel yang memenuhi syarat untuk dimasukkan dalam indeks
+ Jumlah atribut yang diproyeksikan ke dalam indeks
+ Aktivitas tulis di tabel utama selama pembuatan indeks

Jika Anda menambahkan indeks sekunder global ke tabel yang sangat besar, mungkin perlu waktu lama untuk menyelesaikan proses pembuatan. Untuk memantau kemajuan dan menentukan apakah indeks memiliki kapasitas tulis yang memadai, lihat CloudWatch metrik Amazon berikut:
+ `OnlineIndexPercentageProgress`

Untuk informasi selengkapnya tentang CloudWatch metrik yang terkait dengan DynamoDB, lihat. [Metrik DynamoDB](metrics-dimensions.md#dynamodb-metrics)

**penting**  
Anda mungkin perlu mengizinkan daftar tabel yang sangat besar sebelum membuat atau memperbarui Indeks Sekunder Global. Silakan hubungi AWS Support untuk mengizinkan daftar tabel Anda.

Saat indeks sedang melakukan backfill, DynamoDB menggunakan kapasitas sistem internal untuk membaca dari tabel. Hal ini bertujuan untuk meminimalkan dampak pembuatan indeks dan untuk memastikan bahwa tabel Anda tidak kehabisan kapasitas baca.

## Menghapus Indeks Sekunder Global
<a name="GSI.OnlineOps.Deleting"></a>

Jika tidak lagi memerlukan indeks sekunder global, Anda dapat menghapusnya menggunakan operasi `UpdateTable`.

Anda hanya dapat menghapus satu indeks sekunder global per operasi `UpdateTable`.

Saat indeks sekunder global sedang dihapus, aktivitas baca atau tulis apa pun di tabel induk tidak akan terpengaruh. Saat penghapusan sedang berlangsung, Anda masih dapat mengubah throughput yang disediakan pada indeks lain.

**catatan**  
Saat Anda menghapus tabel menggunakan tindakan `DeleteTable`, semua indeks sekunder global pada tabel tersebut juga dihapus.
Akun Anda tidak akan dikenakan biaya untuk operasi penghapusan indeks sekunder global.

## Mengubah Indeks Sekunder Global selama pembuatan
<a name="GSI.OnlineOps.Creating.Modify"></a>

Saat indeks sedang dibuat, Anda dapat menggunakan operasi `DescribeTable` untuk mengetahui fasenya. Deskripsi untuk indeks menyertakan atribut Boolean, `Backfilling`, untuk menunjukkan apakah DynamoDB saat ini memuat indeks dengan item dari tabel. Jika nilai `Backfilling` adalah true, artinya fase alokasi sumber daya sudah selesai dan indeks sekarang melakukan backfill. 

Selama fase backfill, Anda dapat menghapus indeks yang sedang dibuat. Selama fase ini, Anda tidak dapat menambahkan atau menghapus indeks lain di tabel.

**catatan**  
Untuk indeks yang dibuat sebagai bagian dari operasi `CreateTable`, atribut `Backfilling` tidak muncul di output `DescribeTable`. Lihat informasi yang lebih lengkap di [Fase pembuatan indeks](#GSI.OnlineOps.Creating.Phases).

# Mendeteksi dan memperbaiki pelanggaran kunci indeks di DynamoDB
<a name="GSI.OnlineOps.ViolationDetection"></a>

Selama fase backfill pembuatan indeks sekunder global, Amazon DynamoDB memeriksa setiap item dalam tabel untuk menentukan apakah item tersebut memenuhi syarat untuk dimasukkan dalam indeks. Beberapa item mungkin tidak memenuhi syarat karena akan menyebabkan pelanggaran kunci indeks. Dalam kasus ini, item tetap berada di tabel, tetapi indeks tidak memiliki entri yang sesuai untuk item tersebut.

*Pelanggaran kunci indeks* terjadi dalam situasi berikut:
+ Ada ketidakcocokan jenis data antara nilai atribut dan jenis data skema kunci indeks. Misalnya, katakanlah salah satu item dalam tabel `GameScores` memiliki nilai `TopScore` jenis `String`. Jika Anda menambahkan indeks sekunder global dengan kunci partisi `TopScore`, jenis `Number`, item dari tabel tersebut akan melanggar kunci indeks.
+ Nilai atribut dari tabel melebihi panjang maksimum untuk atribut kunci indeks. Panjang maksimum kunci partisi adalah 2048 byte, dan panjang maksimum kunci urutan adalah 1024 byte. Jika salah satu nilai atribut yang sesuai dalam tabel melebihi batas ini, item dari tabel akan melanggar kunci indeks.

**catatan**  
Jika nilai atribut Binari atau String ditetapkan untuk atribut yang digunakan sebagai kunci indeks, maka nilai atribut harus memiliki panjang lebih besar dari nol;, jika tidak, item dari tabel akan melanggar kunci indeks.  
Alat ini tidak menandai pelanggaran kunci indeks ini, saat ini.

Jika pelanggaran kunci indeks terjadi, fase backfill berlanjut tanpa gangguan. Namun, item yang melanggar tidak termasuk dalam indeks. Setelah fase backfill selesai, semua penulisan ke item yang melanggar skema kunci indeks baru akan ditolak.

Untuk mengidentifikasi dan memperbaiki nilai atribut dalam tabel yang melanggar kunci indeks, gunakan alat Detektor Pelanggaran. Untuk menjalankan Detektor Pelanggaran, buat file konfigurasi yang menentukan nama tabel yang akan dipindai, nama dan jenis data kunci partisi indeks sekunder global dan kunci urutan, serta tindakan yang harus diambil jika ditemukan pelanggaran kunci indeks. Detektor Pelanggaran dapat dijalankan dalam salah satu dari dua mode berbeda:
+ **Mode deteksi** — Mendeteksi pelanggaran kunci indeks. Gunakan mode deteksi untuk melaporkan item dalam tabel yang akan menyebabkan pelanggaran kunci dalam indeks sekunder global. (Anda juga dapat meminta agar item tabel yang melanggar ini segera dihapus ketika ditemukan.) Output dari mode deteksi ditulis ke file, yang dapat Anda gunakan untuk analisis lebih lanjut.
+ **Mode koreksi** — Memperbaiki pelanggaran kunci indeks. Dalam mode koreksi, Detektor Pelanggaran membaca file input dengan format yang sama dengan file output dari mode deteksi. Mode koreksi membaca catatan dari file input dan, untuk setiap catatan, mode ini menghapus atau memperbarui item yang sesuai dalam tabel. (Perhatikan bahwa jika Anda memilih untuk memperbarui item, Anda harus mengedit file input dan menetapkan nilai yang sesuai untuk pembaruan ini.)

## Mengunduh dan menjalankan Detektor Pelanggaran
<a name="GSI.OnlineOps.ViolationDetection.Running"></a>

Detektor Pelanggaran tersedia sebagai Java Archive (file `.jar`) yang dapat dieksekusi, dan dapat dijalankan di komputer Windows, macOS, atau Linux. Detektor Pelanggaran membutuhkan Java 1.7 (atau yang lebih baru) dan Apache Maven.
+ [Unduh detektor pelanggaran dari GitHub](https://github.com/awslabs/dynamodb-online-index-violation-detector)

Ikuti petunjuk dalam file `README.md` untuk mengunduh dan menginstal Detektor Pelanggaran menggunakan Maven.

Untuk memulai Detektor Pelanggaran, buka direktori tempat Anda membuat `ViolationDetector.java` dan masukkan perintah berikut.

```
java -jar ViolationDetector.jar [options]
```

Baris perintah Detektor Pelanggaran menerima opsi berikut:
+ `-h | --help` — Mencetak ringkasan penggunaan dan opsi untuk Detektor Pelanggaran.
+ `-p | --configFilePath` `value` — Nama yang sepenuhnya memenuhi syarat untuk file konfigurasi Detektor Pelanggaran. Untuk informasi selengkapnya, lihat [File konfigurasi Detektor Pelanggaran](#GSI.OnlineOps.ViolationDetection.ConfigFile).
+ `-t | --detect` `value` — Mendeteksi pelanggaran kunci indeks di tabel, dan menuliskannya ke file output Detektor Pelanggaran. Jika nilai parameter ini diatur ke `keep`, item dengan pelanggaran kunci tidak diubah. Jika nilai diatur ke `delete`, item dengan pelanggaran kunci dihapus dari tabel.
+ `-c | --correct` `value` — Membaca pelanggaran kunci indeks dari file input, dan mengambil tindakan perbaikan pada item dalam tabel. Jika nilai parameter ini disetel ke `update`, item dengan pelanggaran kunci diperbarui dengan nilai baru yang tidak melanggar. Jika nilai diatur ke `delete`, item dengan pelanggaran kunci dihapus dari tabel.

## File konfigurasi Detektor Pelanggaran
<a name="GSI.OnlineOps.ViolationDetection.ConfigFile"></a>

Saat runtime, alat Detektor Pelanggaran memerlukan file konfigurasi. Parameter dalam file ini menentukan sumber daya DynamoDB yang dapat diakses oleh Detektor Pelanggaran, dan jumlah throughput yang disediakan yang dapat digunakan oleh sumber daya tersebut. Tabel berikut mendeskripsikan parameter ini.


****  

| Nama parameter | Deskripsi | Diperlukan? | 
| --- | --- | --- | 
|  `awsCredentialsFile`  |  Nama yang sepenuhnya memenuhi syarat untuk file yang berisi kredensial AWS Anda. File kredensial harus dalam format berikut: <pre>accessKey = access_key_id_goes_here<br />secretKey = secret_key_goes_here </pre>  |  Ya  | 
|  `dynamoDBRegion`  |   AWS Wilayah di mana tabel berada. Sebagai contoh: `us-west-2`.  |  Ya  | 
|  `tableName`  | Nama tabel DynamoDB yang akan dipindai. |  Ya  | 
|  `gsiHashKeyName`  |  Nama kunci partisi indeks.  |  Ya  | 
|  `gsiHashKeyType`  |  Jenis data kunci partisi indeks—`String`, `Number`, atau `Binary`: `S \| N \| B`  |  Ya  | 
|  `gsiRangeKeyName`  |  Nama kunci urutan indeks. Jangan tentukan parameter ini jika indeks hanya memiliki kunci primer sederhana (kunci partisi).  |  Tidak  | 
|  `gsiRangeKeyType`  |  Jenis data untuk kunci urutan indeks—`String`, `Number`, atau `Binary`: `S \| N \| B`  Jangan tentukan parameter ini jika indeks hanya memiliki kunci primer sederhana (kunci partisi).  |  Tidak  | 
|  `recordDetails`  |  Apakah akan menulis detail lengkap pelanggaran kunci indeks ke file keluaran. Jika diatur ke `true` (default), informasi lengkap tentang item yang melanggar akan dilaporkan. Jika diatur ke `false`, hanya jumlah pelanggaran yang dilaporkan.  |  Tidak  | 
|  `recordGsiValueInViolationRecord`  |  Apakah akan menulis nilai untuk kunci indeks yang melanggar ke file output. Jika diatur ke `true` (default), nilai kunci dilaporkan. Jika diatur ke `false`, nilai kunci tidak dilaporkan.  |  Tidak  | 
|  `detectionOutputPath`  |  Jalur lengkap file output Detektor Pelanggaran. Parameter ini mendukung penulisan ke direktori lokal atau ke Amazon Simple Storage Service (Amazon S3). Berikut ini adalah beberapa contohnya: `detectionOutputPath = ``//local/path/filename.csv` `detectionOutputPath = ``s3://bucket/filename.csv` Informasi dalam file output muncul dalam format nilai yang dipisahkan koma (CSV). Jika Anda tidak mengatur `detectionOutputPath`, file outputnya bernama `violation_detection.csv` dan ditulis ke direktori kerja saat ini.  |  Tidak  | 
|  `numOfSegments`  | Jumlah segmen pemindaian paralel yang akan digunakan saat Detektor Pelanggaran memindai tabel. Nilai defaultnya adalah 1, artinya tabel dipindai secara berurutan. Jika nilainya 2 atau lebih tinggi, Detektor Pelanggaran membagi tabel menjadi banyak segmen logis dan jumlah utas pemindaian yang sama. Pengaturan maksimum untuk `numOfSegments` adalah 4096.Untuk tabel yang lebih besar, pemindaian paralel umumnya lebih cepat daripada pemindaian berurutan. Selain itu, jika tabel cukup besar untuk menjangkau beberapa partisi, pemindaian paralel mendistribusikan aktivitas bacanya secara merata di beberapa partisi.Untuk informasi selengkapnya tentang pemindaian paralel di DynamoDB, lihat [Pemindaian paralel](Scan.md#Scan.ParallelScan). |  Tidak  | 
|  `numOfViolations`  |  Batas atas pelanggaran kunci indeks untuk menulis ke file output. Jika diatur ke `-1` (default), seluruh tabel dipindai. Jika diatur ke angka bulat positif, Detektor Pelanggaran akan berhenti setelah menemukan jumlah pelanggaran tersebut.  |  Tidak  | 
|  `numOfRecords`  |  Jumlah item dalam tabel yang akan dipindai. Jika diatur ke -1 (default), seluruh tabel dipindai. Jika diatur ke angka bulat positif, Detektor Pelanggaran akan berhenti setelah memindai jumlah item tersebut dalam tabel.  |  Tidak  | 
|  `readWriteIOPSPercent`  |  Mengatur persentase unit kapasitas baca yang disediakan yang digunakan selama pemindaian tabel. Nilai yang valid berkisar dari `1` sampai `100`. Nilai default (`25`) berarti bahwa Detektor Pelanggaran akan menggunakan tidak lebih dari 25% dari throughput baca yang disediakan pada tabel.  |  Tidak  | 
|  `correctionInputPath`  |  Jalur lengkap file input koreksi Detektor Pelanggaran. Jika Anda menjalankan Detektor Pelanggaran dalam mode koreksi, konten file ini digunakan untuk mengubah atau menghapus item data dalam tabel yang melanggar indeks sekunder global. Format file `correctionInputPath` sama dengan format file `detectionOutputPath`. Ini memungkinkan Anda memproses output dari mode deteksi sebagai input dalam mode koreksi.  |  Tidak  | 
|  `correctionOutputPath`  |  Jalur lengkap file output koreksi Detektor Pelanggaran. File ini dibuat hanya jika ada kesalahan pembaruan. Parameter ini mendukung penulisan ke direktori lokal atau ke Amazon S3. Berikut ini adalah beberapa contohnya: `correctionOutputPath = ``//local/path/filename.csv` `correctionOutputPath = ``s3://bucket/filename.csv` Informasi dalam file output ditampilkan dalam format CSV. Jika Anda tidak mengatur `correctionOutputPath`, file outputnya bernama `violation_update_errors.csv` dan ditulis ke direktori kerja saat ini.  |  Tidak  | 

## Deteksi
<a name="GSI.OnlineOps.ViolationDetection.Detection"></a>

Untuk mendeteksi pelanggaran kunci indeks, gunakan Detektor Pelanggaran dengan opsi baris perintah `--detect`. Untuk menunjukkan cara kerja opsi ini, pertimbangkan `ProductCatalog` tabel. Berikut ini adalah daftar item dalam tabel. Hanya kunci primer (`Id`) dan atribut `Price` yang ditampilkan.


****  

| Id (kunci primer) | Harga | 
| --- | --- | 
| 101 |  5  | 
| 102 |  20  | 
| 103 | 200  | 
| 201 |  100  | 
| 202 |  200  | 
| 203 |  300  | 
| 204 |  400  | 
| 205 |  500  | 

Semua nilai untuk `Price` berjenis `Number`. Namun, karena DynamoDB tidak memiliki skema, Anda dapat menambahkan item dengan `Price` non-numerik. Misalnya, anggaplah Anda menambahkan item lain ke tabel `ProductCatalog`.


****  

| Id (kunci primer) | Harga | 
| --- | --- | 
| 999 | "Hello" | 

Tabel sekarang memiliki total sembilan item.

Sekarang Anda menambahkan indeks sekunder global baru ke tabel: `PriceIndex`. Kunci primer untuk indeks ini adalah kunci partisi, `Price`, yang berjenis `Number`. Setelah indeks dibuat, indeks akan berisi delapan item—tetapi tabel `ProductCatalog` memiliki sembilan item. Alasan perbedaan ini adalah bahwa nilai `"Hello"` adalah jenis `String`, tetapi `PriceIndex` memiliki kunci primer jenis `Number`. Nilai `String` melanggar kunci indeks sekunder global, sehingga tidak ada dalam indeks.

Untuk menggunakan Detektor Pelanggaran dalam skenario ini, Anda akan membuat file konfigurasi seperti berikut ini terlebih dahulu.

```
# Properties file for violation detection tool configuration.
# Parameters that are not specified will use default values.

awsCredentialsFile = /home/alice/credentials.txt
dynamoDBRegion = us-west-2
tableName = ProductCatalog
gsiHashKeyName = Price
gsiHashKeyType = N
recordDetails = true
recordGsiValueInViolationRecord = true
detectionOutputPath = ./gsi_violation_check.csv
correctionInputPath = ./gsi_violation_check.csv
numOfSegments = 1
readWriteIOPSPercent = 40
```

Selanjutnya, Anda menjalankan Detektor Pelanggaran seperti dalam contoh berikut.

```
$  java -jar ViolationDetector.jar --configFilePath config.txt --detect keep

Violation detection started: sequential scan, Table name: ProductCatalog, GSI name: PriceIndex
Progress: Items scanned in total: 9,    Items scanned by this thread: 9,    Violations found by this thread: 1, Violations deleted by this thread: 0
Violation detection finished: Records scanned: 9, Violations found: 1, Violations deleted: 0, see results at: ./gsi_violation_check.csv
```

Jika parameter konfigurasi `recordDetails` diatur ke `true`, Detektor Pelanggaran menulis detail setiap pelanggaran ke file output, seperti dalam contoh berikut.

```
Table Hash Key,GSI Hash Key Value,GSI Hash Key Violation Type,GSI Hash Key Violation Description,GSI Hash Key Update Value(FOR USER),Delete Blank Attributes When Updating?(Y/N) 

999,"{""S"":""Hello""}",Type Violation,Expected: N Found: S,,
```

File output dalam format CSV. Baris pertama dalam file tersebut adalah header, diikuti oleh satu catatan per item yang melanggar kunci indeks. Bidang catatan pelanggaran tersebut adalah sebagai berikut:
+ **Kunci hash tabel** — Nilai kunci partisi item dalam tabel.
+ **Kunci rentang tabel** — Nilai kunci urutan item dalam tabel.
+ **Nilai kunci hash GSI** — Nilai kunci partisi indeks sekunder global.
+ **Jenis pelanggaran kunci hash GSI** — `Type Violation` atau `Size Violation`.
+ **Deskripsi pelanggaran kunci hash GSI** — Penyebab pelanggaran.
+ **Nilai pembaruan kunci hash GSI (UNTUK PENGGUNA)** — Dalam mode koreksi, nilai baru yang diberikan pengguna untuk atribut tersebut.
+ **Nilai kunci rentang GSI** — Nilai kunci urutan indeks sekunder global.
+ **Jenis pelanggaran kunci rentang GSI** — `Type Violation` atau `Size Violation`.
+ **Deskripsi pelanggaran kunci rentang GSI** — Penyebab pelanggaran.
+ **Nilai pembaruan kunci rentang GSI (UNTUK PENGGUNA)** — Dalam mode koreksi, nilai baru yang diberikan pengguna untuk atribut tersebut.
+ **Hapus atribut kosong saat memperbarui (Y/T)** — Dalam mode koreksi, menentukan apakah akan menghapus (Y) atau menyimpan (T) item yang melanggar dalam tabel—tetapi hanya jika salah satu bidang berikut ini kosong:
  + `GSI Hash Key Update Value(FOR USER)`
  + `GSI Range Key Update Value(FOR USER)`

  Jika salah satu dari bidang ini tidak kosong, `Delete Blank Attribute When Updating(Y/N)` tidak berpengaruh.

**catatan**  
Format output mungkin berbeda, tergantung file konfigurasi dan opsi baris perintah. Misalnya, jika tabel memiliki kunci primer sederhana (tanpa kunci urutan), tidak ada bidang kunci urutan yang akan ditampilkan dalam output.  
Catatan pelanggaran dalam file mungkin tidak diurutkan.

## Koreksi
<a name="GSI.OnlineOps.ViolationDetection.Correction"></a>

Untuk memperbaiki pelanggaran kunci indeks, gunakan Detektor Pelanggaran dengan opsi baris perintah `--correct`. Dalam mode koreksi, Detektor Pelanggaran membaca file input yang ditentukan oleh parameter `correctionInputPath`. File ini memiliki format yang sama dengan file `detectionOutputPath`, sehingga Anda dapat menggunakan output dari deteksi sebagai input untuk koreksi.

Detektor Pelanggaran menyediakan dua cara berbeda untuk memperbaiki pelanggaran kunci indeks:
+ **Hapus pelanggaran** — Menghapus item tabel yang memiliki nilai atribut yang melanggar.
+ **Perbarui pelanggaran** — Memperbarui item tabel, mengganti atribut yang melanggar dengan nilai yang tidak melanggar.

Dalam kasus tersebut, Anda dapat menggunakan file output dari mode deteksi sebagai input untuk mode koreksi.

Melanjutkan contoh `ProductCatalog`, misalkan Anda ingin menghapus item yang melanggar dari tabel. Untuk melakukannya, gunakan perintah berikut.

```
$  java -jar ViolationDetector.jar --configFilePath config.txt --correct delete
```

Pada tahap ini, Anda akan diminta untuk mengonfirmasi apakah Anda ingin menghapus item yang melanggar.

```
Are you sure to delete all violations on the table?y/n
y
Confirmed, will delete violations on the table...
Violation correction from file started: Reading records from file: ./gsi_violation_check.csv, will delete these records from table.
Violation correction from file finished: Violations delete: 1, Violations Update: 0
```

Sekarang, `ProductCatalog` dan `PriceIndex` memiliki jumlah item yang sama.

# Menggunakan Indeks Sekunder Global: Java
<a name="GSIJavaDocumentAPI"></a>

Anda dapat menggunakan AWS SDK untuk Java Document API untuk membuat tabel Amazon DynamoDB dengan satu atau beberapa indeks sekunder global, menjelaskan indeks pada tabel, dan melakukan kueri menggunakan indeks. 

Berikut ini adalah langkah-langkah umum untuk operasi tabel. 

1. Buat instans dari kelas `DynamoDB`.

1. Berikan parameter wajib dan opsional untuk operasi dengan membuat objek permintaan yang sesuai. 

1. Panggil metode sesuai yang ditentukan oleh klien yang Anda buat pada langkah sebelumnya. 

**Topics**
+ [Membuat tabel dengan Indeks Sekunder Global](#GSIJavaDocumentAPI.CreateTableWithIndex)
+ [Mendeskripsikan tabel dengan Indeks Sekunder Global](#GSIJavaDocumentAPI.DescribeTableWithIndex)
+ [Mengkueri Indeks Sekunder Global](#GSIJavaDocumentAPI.QueryAnIndex)
+ [Contoh: Indeks Sekunder Global menggunakan API AWS SDK untuk Java dokumen](GSIJavaDocumentAPI.Example.md)

## Membuat tabel dengan Indeks Sekunder Global
<a name="GSIJavaDocumentAPI.CreateTableWithIndex"></a>

Anda dapat membuat indeks sekunder global pada saat membuat tabel. Untuk melakukannya, gunakan `CreateTable` dan berikan spesifikasi Anda untuk satu atau beberapa indeks sekunder global. Contoh kode Java berikut membuat tabel untuk menyimpan informasi tentang data cuaca. Kunci partisinya adalah `Location` dan kunci urutannya adalah `Date`. Indeks sekunder global bernama `PrecipIndex` memungkinkan akses cepat ke data curah hujan untuk berbagai lokasi.

Berikut adalah langkah-langkah untuk membuat tabel dengan indeks sekunder global, menggunakan API dokumen DynamoDB. 

1. Buat instans dari kelas `DynamoDB`.

1. Buat instans dari kelas `CreateTableRequest` untuk memberikan informasi permintaan.

   Anda harus memberikan nama tabel, kunci primernya, dan nilai throughput yang ditentukan. Untuk indeks sekunder global, Anda harus memberikan nama indeks, pengaturan throughput yang ditentukan, definisi atribut untuk kunci urutan indeks, skema kunci untuk indeks, dan proyeksi atribut.

1. Panggil metode `createTable` dengan menentukan objek permintaan sebagai parameter.

Contoh kode Java berikut mendemonstrasikan langkah sebelumnya. Kode tersebut membuat tabel (`WeatherData`) dengan indeks sekunder global (`PrecipIndex`). Kunci partisi indeksnya adalah `Date` dan kunci urutannya adalah `Precipitation`. Semua atribut tabel diproyeksikan ke dalam indeks. Pengguna dapat mengkueri indeks ini untuk mendapatkan data cuaca untuk tanggal tertentu, yang secara opsional mengurutkan data berdasarkan jumlah curah hujan. 

Karena `Precipitation` bukan atribut kunci untuk tabel tersebut, maka tidak diperlukan. Namun, item `WeatherData` tanpa `Precipitation` tidak muncul di `PrecipIndex`.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

// Attribute definitions
ArrayList<AttributeDefinition> attributeDefinitions = new ArrayList<AttributeDefinition>();

attributeDefinitions.add(new AttributeDefinition()
    .withAttributeName("Location")
    .withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition()
    .withAttributeName("Date")
    .withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition()
    .withAttributeName("Precipitation")
    .withAttributeType("N"));

// Table key schema
ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>();
tableKeySchema.add(new KeySchemaElement()
    .withAttributeName("Location")
    .withKeyType(KeyType.HASH));  //Partition key
tableKeySchema.add(new KeySchemaElement()
    .withAttributeName("Date")
    .withKeyType(KeyType.RANGE));  //Sort key

// PrecipIndex
GlobalSecondaryIndex precipIndex = new GlobalSecondaryIndex()
    .withIndexName("PrecipIndex")
    .withProvisionedThroughput(new ProvisionedThroughput()
        .withReadCapacityUnits((long) 10)
        .withWriteCapacityUnits((long) 1))
        .withProjection(new Projection().withProjectionType(ProjectionType.ALL));

ArrayList<KeySchemaElement> indexKeySchema = new ArrayList<KeySchemaElement>();

indexKeySchema.add(new KeySchemaElement()
    .withAttributeName("Date")
    .withKeyType(KeyType.HASH));  //Partition key
indexKeySchema.add(new KeySchemaElement()
    .withAttributeName("Precipitation")
    .withKeyType(KeyType.RANGE));  //Sort key

precipIndex.setKeySchema(indexKeySchema);

CreateTableRequest createTableRequest = new CreateTableRequest()
    .withTableName("WeatherData")
    .withProvisionedThroughput(new ProvisionedThroughput()
        .withReadCapacityUnits((long) 5)
        .withWriteCapacityUnits((long) 1))
    .withAttributeDefinitions(attributeDefinitions)
    .withKeySchema(tableKeySchema)
    .withGlobalSecondaryIndexes(precipIndex);

Table table = dynamoDB.createTable(createTableRequest);
System.out.println(table.getDescription());
```

Anda harus menunggu hingga DynamoDB membuat tabel dan menetapkan status tabel menjadi `ACTIVE`. Setelah itu, Anda bisa mulai memasukkan item data ke dalam tabel.

## Mendeskripsikan tabel dengan Indeks Sekunder Global
<a name="GSIJavaDocumentAPI.DescribeTableWithIndex"></a>

Untuk mendapatkan informasi tentang indeks sekunder global pada sebuah tabel, gunakan `DescribeTable`. Untuk setiap indeks, Anda dapat mengakses namanya, skema kunci, dan atribut yang diproyeksikan.

Berikut ini adalah langkah-langkah untuk mengakses informasi indeks sekunder global sebuah tabel. 

1. Buat instans dari kelas `DynamoDB`.

1. Buat instans dari kelas `Table` untuk mewakili indeks yang ingin Anda gunakan.

1. Panggil metode `describe` pada objek `Table`.

Contoh kode Java berikut mendemonstrasikan langkah sebelumnya.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("WeatherData");
TableDescription tableDesc = table.describe();
    

Iterator<GlobalSecondaryIndexDescription> gsiIter = tableDesc.getGlobalSecondaryIndexes().iterator();
while (gsiIter.hasNext()) {
    GlobalSecondaryIndexDescription gsiDesc = gsiIter.next();
    System.out.println("Info for index "
         + gsiDesc.getIndexName() + ":");

    Iterator<KeySchemaElement> kseIter = gsiDesc.getKeySchema().iterator();
    while (kseIter.hasNext()) {
        KeySchemaElement kse = kseIter.next();
        System.out.printf("\t%s: %s\n", kse.getAttributeName(), kse.getKeyType());
    }
    Projection projection = gsiDesc.getProjection();
    System.out.println("\tThe projection type is: "
        + projection.getProjectionType());
    if (projection.getProjectionType().toString().equals("INCLUDE")) {
        System.out.println("\t\tThe non-key projected attributes are: "
            + projection.getNonKeyAttributes());
    }
}
```

## Mengkueri Indeks Sekunder Global
<a name="GSIJavaDocumentAPI.QueryAnIndex"></a>

Anda dapat menggunakan `Query` pada indeks sekunder global, sama seperti Anda `Query` tabel. Anda perlu menentukan nama indeks, kriteria kueri untuk kunci partisi indeks dan kunci urutan (jika ada), dan atribut yang ingin Anda kembalikan. Dalam contoh ini, indeks adalah `PrecipIndex`, yang memiliki kunci partisi `Date` dan kunci urutan `Precipitation`. Kueri indeks mengembalikan semua data cuaca untuk tanggal tertentu, dengan curah hujan lebih besar dari nol.

Berikut ini adalah langkah-langkah untuk query indeks sekunder global menggunakan AWS SDK untuk Java Document API. 

1. Buat instans dari kelas `DynamoDB`.

1. Buat instans dari kelas `Table` untuk mewakili indeks yang ingin Anda gunakan.

1. Buat instans dari kelas `Index` untuk indeks yang ingin Anda kueri.

1. Panggil metode `query` pada objek `Index`.

Nama atribut `Date` adalah kata yang disimpan DynamoDB. Oleh karena itu, Anda harus menggunakan nama atribut ekspresi sebagai placeholder di `KeyConditionExpression`.

Contoh kode Java berikut mendemonstrasikan langkah sebelumnya.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("WeatherData");
Index index = table.getIndex("PrecipIndex");

QuerySpec spec = new QuerySpec()
    .withKeyConditionExpression("#d = :v_date and Precipitation = :v_precip")
    .withNameMap(new NameMap()
        .with("#d", "Date"))
    .withValueMap(new ValueMap()
        .withString(":v_date","2013-08-10")
        .withNumber(":v_precip",0));

ItemCollection<QueryOutcome> items = index.query(spec);
Iterator<Item> iter = items.iterator(); 
while (iter.hasNext()) {
    System.out.println(iter.next().toJSONPretty());
}
```

# Contoh: Indeks Sekunder Global menggunakan API AWS SDK untuk Java dokumen
<a name="GSIJavaDocumentAPI.Example"></a>

Contoh kode Java berikut menunjukkan cara menggunakan indeks sekunder global. Contoh tersebut membuat tabel bernama `Issues`, yang dapat digunakan dalam sistem pelacakan bug sederhana untuk pengembangan perangkat lunak. Kunci partisinya adalah `IssueId` dan kunci urutannya adalah `Title`. Ada tiga indeks sekunder global pada tabel ini:
+ `CreateDateIndex` — Kunci partisinya adalah `CreateDate` dan kunci urutannya adalah `IssueId`. Selain kunci tabel, atribut `Description` dan `Status` diproyeksikan ke dalam indeks.
+ `TitleIndex` — Kunci partisinya adalah `Title` dan kunci urutannya adalah `IssueId`. Tidak ada atribut selain kunci tabel yang diproyeksikan ke dalam indeks.
+ `DueDateIndex` — Kunci partisinya adalah `DueDate`, dan tidak ada kunci urutan. Semua atribut tabel diproyeksikan ke dalam indeks.

Setelah tabel `Issues` dibuat, program memuat tabel dengan data yang mewakili laporan bug perangkat lunak. Kemudian, data dikueri menggunakan indeks sekunder global. Terakhir, program menghapus tabel `Issues`.

Untuk step-by-step instruksi untuk menguji contoh berikut, lihat[Contoh kode Java](CodeSamples.Java.md).

**Example**  

```
package com.amazonaws.codesamples.document;

import java.util.ArrayList;
import java.util.Iterator;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Index;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;
import com.amazonaws.services.dynamodbv2.document.QueryOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.QuerySpec;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.Projection;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;

public class DocumentAPIGlobalSecondaryIndexExample {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    public static String tableName = "Issues";

    public static void main(String[] args) throws Exception {

        createTable();
        loadData();

        queryIndex("CreateDateIndex");
        queryIndex("TitleIndex");
        queryIndex("DueDateIndex");

        deleteTable(tableName);

    }

    public static void createTable() {

        // Attribute definitions
        ArrayList<AttributeDefinition> attributeDefinitions = new ArrayList<AttributeDefinition>();

        attributeDefinitions.add(new AttributeDefinition().withAttributeName("IssueId").withAttributeType("S"));
        attributeDefinitions.add(new AttributeDefinition().withAttributeName("Title").withAttributeType("S"));
        attributeDefinitions.add(new AttributeDefinition().withAttributeName("CreateDate").withAttributeType("S"));
        attributeDefinitions.add(new AttributeDefinition().withAttributeName("DueDate").withAttributeType("S"));

        // Key schema for table
        ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>();
        tableKeySchema.add(new KeySchemaElement().withAttributeName("IssueId").withKeyType(KeyType.HASH)); // Partition
                                                                                                           // key
        tableKeySchema.add(new KeySchemaElement().withAttributeName("Title").withKeyType(KeyType.RANGE)); // Sort
                                                                                                          // key

        // Initial provisioned throughput settings for the indexes
        ProvisionedThroughput ptIndex = new ProvisionedThroughput().withReadCapacityUnits(1L)
                .withWriteCapacityUnits(1L);

        // CreateDateIndex
        GlobalSecondaryIndex createDateIndex = new GlobalSecondaryIndex().withIndexName("CreateDateIndex")
                .withProvisionedThroughput(ptIndex)
                .withKeySchema(new KeySchemaElement().withAttributeName("CreateDate").withKeyType(KeyType.HASH), // Partition
                                                                                                                 // key
                        new KeySchemaElement().withAttributeName("IssueId").withKeyType(KeyType.RANGE)) // Sort
                                                                                                        // key
                .withProjection(
                        new Projection().withProjectionType("INCLUDE").withNonKeyAttributes("Description", "Status"));

        // TitleIndex
        GlobalSecondaryIndex titleIndex = new GlobalSecondaryIndex().withIndexName("TitleIndex")
                .withProvisionedThroughput(ptIndex)
                .withKeySchema(new KeySchemaElement().withAttributeName("Title").withKeyType(KeyType.HASH), // Partition
                                                                                                            // key
                        new KeySchemaElement().withAttributeName("IssueId").withKeyType(KeyType.RANGE)) // Sort
                                                                                                        // key
                .withProjection(new Projection().withProjectionType("KEYS_ONLY"));

        // DueDateIndex
        GlobalSecondaryIndex dueDateIndex = new GlobalSecondaryIndex().withIndexName("DueDateIndex")
                .withProvisionedThroughput(ptIndex)
                .withKeySchema(new KeySchemaElement().withAttributeName("DueDate").withKeyType(KeyType.HASH)) // Partition
                                                                                                              // key
                .withProjection(new Projection().withProjectionType("ALL"));

        CreateTableRequest createTableRequest = new CreateTableRequest().withTableName(tableName)
                .withProvisionedThroughput(
                        new ProvisionedThroughput().withReadCapacityUnits((long) 1).withWriteCapacityUnits((long) 1))
                .withAttributeDefinitions(attributeDefinitions).withKeySchema(tableKeySchema)
                .withGlobalSecondaryIndexes(createDateIndex, titleIndex, dueDateIndex);

        System.out.println("Creating table " + tableName + "...");
        dynamoDB.createTable(createTableRequest);

        // Wait for table to become active
        System.out.println("Waiting for " + tableName + " to become ACTIVE...");
        try {
            Table table = dynamoDB.getTable(tableName);
            table.waitForActive();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void queryIndex(String indexName) {

        Table table = dynamoDB.getTable(tableName);

        System.out.println("\n***********************************************************\n");
        System.out.print("Querying index " + indexName + "...");

        Index index = table.getIndex(indexName);

        ItemCollection<QueryOutcome> items = null;

        QuerySpec querySpec = new QuerySpec();

        if (indexName == "CreateDateIndex") {
            System.out.println("Issues filed on 2013-11-01");
            querySpec.withKeyConditionExpression("CreateDate = :v_date and begins_with(IssueId, :v_issue)")
                    .withValueMap(new ValueMap().withString(":v_date", "2013-11-01").withString(":v_issue", "A-"));
            items = index.query(querySpec);
        } else if (indexName == "TitleIndex") {
            System.out.println("Compilation errors");
            querySpec.withKeyConditionExpression("Title = :v_title and begins_with(IssueId, :v_issue)")
                    .withValueMap(
                            new ValueMap().withString(":v_title", "Compilation error").withString(":v_issue", "A-"));
            items = index.query(querySpec);
        } else if (indexName == "DueDateIndex") {
            System.out.println("Items that are due on 2013-11-30");
            querySpec.withKeyConditionExpression("DueDate = :v_date")
                    .withValueMap(new ValueMap().withString(":v_date", "2013-11-30"));
            items = index.query(querySpec);
        } else {
            System.out.println("\nNo valid index name provided");
            return;
        }

        Iterator<Item> iterator = items.iterator();

        System.out.println("Query: printing results...");

        while (iterator.hasNext()) {
            System.out.println(iterator.next().toJSONPretty());
        }

    }

    public static void deleteTable(String tableName) {

        System.out.println("Deleting table " + tableName + "...");

        Table table = dynamoDB.getTable(tableName);
        table.delete();

        // Wait for table to be deleted
        System.out.println("Waiting for " + tableName + " to be deleted...");
        try {
            table.waitForDelete();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void loadData() {

        System.out.println("Loading data into table " + tableName + "...");

        // IssueId, Title,
        // Description,
        // CreateDate, LastUpdateDate, DueDate,
        // Priority, Status

        putItem("A-101", "Compilation error", "Can't compile Project X - bad version number. What does this mean?",
                "2013-11-01", "2013-11-02", "2013-11-10", 1, "Assigned");

        putItem("A-102", "Can't read data file", "The main data file is missing, or the permissions are incorrect",
                "2013-11-01", "2013-11-04", "2013-11-30", 2, "In progress");

        putItem("A-103", "Test failure", "Functional test of Project X produces errors", "2013-11-01", "2013-11-02",
                "2013-11-10", 1, "In progress");

        putItem("A-104", "Compilation error", "Variable 'messageCount' was not initialized.", "2013-11-15",
                "2013-11-16", "2013-11-30", 3, "Assigned");

        putItem("A-105", "Network issue", "Can't ping IP address 127.0.0.1. Please fix this.", "2013-11-15",
                "2013-11-16", "2013-11-19", 5, "Assigned");

    }

    public static void putItem(

            String issueId, String title, String description, String createDate, String lastUpdateDate, String dueDate,
            Integer priority, String status) {

        Table table = dynamoDB.getTable(tableName);

        Item item = new Item().withPrimaryKey("IssueId", issueId).withString("Title", title)
                .withString("Description", description).withString("CreateDate", createDate)
                .withString("LastUpdateDate", lastUpdateDate).withString("DueDate", dueDate)
                .withNumber("Priority", priority).withString("Status", status);

        table.putItem(item);
    }

}
```

# Menggunakan Indek Sekunder Global: .NET
<a name="GSILowLevelDotNet"></a>

Anda dapat menggunakan API AWS SDK untuk .NET tingkat rendah untuk membuat tabel Amazon DynamoDB dengan satu atau beberapa indeks sekunder global, menjelaskan indeks pada tabel, dan melakukan kueri menggunakan indeks. Operasi ini dipetakan ke operasi DynamoDB yang sesuai. Untuk informasi selengkapnya, lihat [Referensi Amazon DynamoDB API](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/). 

Berikut ini adalah langkah-langkah umum untuk operasi tabel menggunakan API tingkat rendah .NET. 

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Berikan parameter wajib dan opsional untuk operasi dengan membuat objek permintaan yang sesuai.

   Misalnya, buat objek `CreateTableRequest` untuk membuat tabel dan objek `QueryRequest` untuk mengkueri tabel atau indeks. 

1. Jalankan metode sesuai yang ditentukan oleh klien yang Anda buat pada langkah sebelumnya. 

**Topics**
+ [Membuat tabel dengan Indeks Sekunder Global](#GSILowLevelDotNet.CreateTableWithIndex)
+ [Mendeskripsikan tabel dengan Indeks Sekunder Global](#GSILowLevelDotNet.DescribeTableWithIndex)
+ [Mengkueri Indeks Sekunder Global](#GSILowLevelDotNet.QueryAnIndex)
+ [Contoh: Indeks Sekunder Global menggunakan API tingkat AWS SDK untuk .NET rendah](GSILowLevelDotNet.Example.md)

## Membuat tabel dengan Indeks Sekunder Global
<a name="GSILowLevelDotNet.CreateTableWithIndex"></a>

Anda dapat membuat indeks sekunder global pada saat membuat tabel. Untuk melakukannya, gunakan `CreateTable` dan berikan spesifikasi Anda untuk satu atau beberapa indeks sekunder global. Contoh kode C\$1 berikut membuat tabel untuk menyimpan informasi tentang data cuaca. Kunci partisinya adalah `Location` dan kunci urutannya adalah `Date`. Indeks sekunder global bernama `PrecipIndex` memungkinkan akses cepat ke data curah hujan untuk berbagai lokasi.

Berikut ini adalah langkah-langkah untuk membuat tabel dengan indeks sekunder global, menggunakan API tingkat rendah .NET. 

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Buat instans dari kelas `CreateTableRequest` untuk memberikan informasi permintaan. 

   Anda harus memberikan nama tabel, kunci primernya, dan nilai throughput yang ditentukan. Untuk indeks sekunder global, Anda harus memberikan nama indeks, pengaturan throughput yang ditentukan, definisi atribut untuk kunci urutan indeks, skema kunci untuk indeks, dan proyeksi atribut.

1. Jalankan metode `CreateTable` dengan menentukan objek permintaan sebagai parameter.

Contoh kode \$1C berikut mendemonstrasikan langkah sebelumnya. Kode tersebut membuat tabel (`WeatherData`) dengan indeks sekunder global (`PrecipIndex`). Kunci partisi indeksnya adalah `Date` dan kunci urutannya adalah `Precipitation`. Semua atribut tabel diproyeksikan ke dalam indeks. Pengguna dapat mengkueri indeks ini untuk mendapatkan data cuaca untuk tanggal tertentu, yang secara opsional mengurutkan data berdasarkan jumlah curah hujan. 

Karena `Precipitation` bukan atribut kunci untuk tabel tersebut, maka tidak diperlukan. Namun, item `WeatherData` tanpa `Precipitation` tidak muncul di `PrecipIndex`.

```
client = new AmazonDynamoDBClient();
string tableName = "WeatherData";

// Attribute definitions
var attributeDefinitions = new List<AttributeDefinition>()
{
    {new AttributeDefinition{
        AttributeName = "Location",
        AttributeType = "S"}},
    {new AttributeDefinition{
        AttributeName = "Date",
        AttributeType = "S"}},
    {new AttributeDefinition(){
        AttributeName = "Precipitation",
        AttributeType = "N"}
    }
};

// Table key schema
var tableKeySchema = new List<KeySchemaElement>()
{
    {new KeySchemaElement {
        AttributeName = "Location",
        KeyType = "HASH"}},  //Partition key
    {new KeySchemaElement {
        AttributeName = "Date",
        KeyType = "RANGE"}  //Sort key
    }
};

// PrecipIndex
var precipIndex = new GlobalSecondaryIndex
{
    IndexName = "PrecipIndex",
    ProvisionedThroughput = new ProvisionedThroughput
    {
        ReadCapacityUnits = (long)10,
        WriteCapacityUnits = (long)1
    },
    Projection = new Projection { ProjectionType = "ALL" }
};

var indexKeySchema = new List<KeySchemaElement> {
    {new KeySchemaElement { AttributeName = "Date", KeyType = "HASH"}},  //Partition key
    {new KeySchemaElement{AttributeName = "Precipitation",KeyType = "RANGE"}}  //Sort key
};

precipIndex.KeySchema = indexKeySchema;

CreateTableRequest createTableRequest = new CreateTableRequest
{
    TableName = tableName,
    ProvisionedThroughput = new ProvisionedThroughput
    {
        ReadCapacityUnits = (long)5,
        WriteCapacityUnits = (long)1
    },
    AttributeDefinitions = attributeDefinitions,
    KeySchema = tableKeySchema,
    GlobalSecondaryIndexes = { precipIndex }
};

CreateTableResponse response = client.CreateTable(createTableRequest);
Console.WriteLine(response.CreateTableResult.TableDescription.TableName);
Console.WriteLine(response.CreateTableResult.TableDescription.TableStatus);
```

Anda harus menunggu hingga DynamoDB membuat tabel dan menetapkan status tabel menjadi `ACTIVE`. Setelah itu, Anda bisa mulai memasukkan item data ke dalam tabel.

## Mendeskripsikan tabel dengan Indeks Sekunder Global
<a name="GSILowLevelDotNet.DescribeTableWithIndex"></a>

Untuk mendapatkan informasi tentang indeks sekunder global pada sebuah tabel, gunakan `DescribeTable`. Untuk setiap indeks, Anda dapat mengakses namanya, skema kunci, dan atribut yang diproyeksikan.

Berikut ini adalah langkah-langkah untuk mengakses informasi indeks sekunder global untuk tabel menggunakan API tingkat rendah .NET. 

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Jalankan metode `describeTable` dengan menyediakan objek permintaan sebagai parameter.

   Buat instans dari kelas `DescribeTableRequest` untuk memberikan informasi permintaan. Anda harus memberikan nama tabel.

Contoh kode \$1C berikut mendemonstrasikan langkah sebelumnya.

**Example**  

```
client = new AmazonDynamoDBClient();
string tableName = "WeatherData";

DescribeTableResponse response = client.DescribeTable(new DescribeTableRequest { TableName = tableName});

List<GlobalSecondaryIndexDescription> globalSecondaryIndexes =
response.DescribeTableResult.Table.GlobalSecondaryIndexes;

// This code snippet will work for multiple indexes, even though
// there is only one index in this example.

foreach (GlobalSecondaryIndexDescription gsiDescription in globalSecondaryIndexes) {
     Console.WriteLine("Info for index " + gsiDescription.IndexName + ":");

     foreach (KeySchemaElement kse in gsiDescription.KeySchema) {
          Console.WriteLine("\t" + kse.AttributeName + ": key type is " + kse.KeyType);
     }

      Projection projection = gsiDescription.Projection;
      Console.WriteLine("\tThe projection type is: " + projection.ProjectionType);

      if (projection.ProjectionType.ToString().Equals("INCLUDE")) {
           Console.WriteLine("\t\tThe non-key projected attributes are: "
                + projection.NonKeyAttributes);
      }
}
```

## Mengkueri Indeks Sekunder Global
<a name="GSILowLevelDotNet.QueryAnIndex"></a>

Anda dapat menggunakan `Query` pada indeks sekunder global, sama seperti Anda `Query` tabel. Anda perlu menentukan nama indeks, kriteria kueri untuk kunci partisi indeks dan kunci urutan (jika ada), dan atribut yang ingin Anda kembalikan. Dalam contoh ini, indeks adalah `PrecipIndex`, yang memiliki kunci partisi `Date` dan kunci urutan `Precipitation`. Kueri indeks mengembalikan semua data cuaca untuk tanggal tertentu, dengan curah hujan lebih besar dari nol.

Berikut ini adalah langkah-langkah untuk mengkueri indeks sekunder global menggunakan API tingkat rendah .NET. 

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Buat instans dari kelas `QueryRequest` untuk memberikan informasi permintaan.

1. Jalankan metode `query` dengan menentukan objek permintaan sebagai parameter.

Nama atribut `Date` adalah kata yang disimpan DynamoDB. Oleh karena itu, Anda harus menggunakan nama atribut ekspresi sebagai placeholder di `KeyConditionExpression`.

Contoh kode \$1C berikut mendemonstrasikan langkah sebelumnya.

**Example**  

```
client = new AmazonDynamoDBClient();

QueryRequest queryRequest = new QueryRequest
{
    TableName = "WeatherData",
    IndexName = "PrecipIndex",
    KeyConditionExpression = "#dt = :v_date and Precipitation > :v_precip",
    ExpressionAttributeNames = new Dictionary<String, String> {
        {"#dt", "Date"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue> {
        {":v_date", new AttributeValue { S =  "2013-08-01" }},
        {":v_precip", new AttributeValue { N =  "0" }}
    },
    ScanIndexForward = true
};

var result = client.Query(queryRequest);

var items = result.Items;
foreach (var currentItem in items)
{
    foreach (string attr in currentItem.Keys)
    {
        Console.Write(attr + "---> ");
        if (attr == "Precipitation")
        {
            Console.WriteLine(currentItem[attr].N);
    }
    else
    {
        Console.WriteLine(currentItem[attr].S);
    }

         }
     Console.WriteLine();
}
```

# Contoh: Indeks Sekunder Global menggunakan API tingkat AWS SDK untuk .NET rendah
<a name="GSILowLevelDotNet.Example"></a>

Contoh kode C\$1 berikut menunjukkan cara menggunakan indeks sekunder global. Contoh tersebut membuat tabel bernama `Issues`, yang dapat digunakan dalam sistem pelacakan bug sederhana untuk pengembangan perangkat lunak. Kunci partisinya adalah `IssueId` dan kunci urutannya adalah `Title`. Ada tiga indeks sekunder global pada tabel ini:
+ `CreateDateIndex` — Kunci partisinya adalah `CreateDate` dan kunci urutannya adalah `IssueId`. Selain kunci tabel, atribut `Description` dan `Status` diproyeksikan ke dalam indeks.
+ `TitleIndex` — Kunci partisinya adalah `Title` dan kunci urutannya adalah `IssueId`. Tidak ada atribut selain kunci tabel yang diproyeksikan ke dalam indeks.
+ `DueDateIndex` — Kunci partisinya adalah `DueDate`, dan tidak ada kunci urutan. Semua atribut tabel diproyeksikan ke dalam indeks.

Setelah tabel `Issues` dibuat, program memuat tabel dengan data yang mewakili laporan bug perangkat lunak. Kemudian, data dikueri menggunakan indeks sekunder global. Terakhir, program menghapus tabel `Issues`.

Untuk step-by-step petunjuk pengujian sampel berikut, lihat[Contoh kode .NET](CodeSamples.DotNet.md).

**Example**  

```
using System;
using System.Collections.Generic;
using System.Linq;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;
using Amazon.SecurityToken;

namespace com.amazonaws.codesamples
{
    class LowLevelGlobalSecondaryIndexExample
    {
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();
        public static String tableName = "Issues";

        public static void Main(string[] args)
        {
            CreateTable();
            LoadData();

            QueryIndex("CreateDateIndex");
            QueryIndex("TitleIndex");
            QueryIndex("DueDateIndex");

            DeleteTable(tableName);

            Console.WriteLine("To continue, press enter");
            Console.Read();
        }

        private static void CreateTable()
        {
            // Attribute definitions
            var attributeDefinitions = new List<AttributeDefinition>()
        {
            {new AttributeDefinition {
                 AttributeName = "IssueId", AttributeType = "S"
             }},
            {new AttributeDefinition {
                 AttributeName = "Title", AttributeType = "S"
             }},
            {new AttributeDefinition {
                 AttributeName = "CreateDate", AttributeType = "S"
             }},
            {new AttributeDefinition {
                 AttributeName = "DueDate", AttributeType = "S"
             }}
        };

            // Key schema for table
            var tableKeySchema = new List<KeySchemaElement>() {
            {
                new KeySchemaElement {
                    AttributeName= "IssueId",
                    KeyType = "HASH" //Partition key
                }
            },
            {
                new KeySchemaElement {
                    AttributeName = "Title",
                    KeyType = "RANGE" //Sort key
                }
            }
        };

            // Initial provisioned throughput settings for the indexes
            var ptIndex = new ProvisionedThroughput
            {
                ReadCapacityUnits = 1L,
                WriteCapacityUnits = 1L
            };

            // CreateDateIndex
            var createDateIndex = new GlobalSecondaryIndex()
            {
                IndexName = "CreateDateIndex",
                ProvisionedThroughput = ptIndex,
                KeySchema = {
                new KeySchemaElement {
                    AttributeName = "CreateDate", KeyType = "HASH" //Partition key
                },
                new KeySchemaElement {
                    AttributeName = "IssueId", KeyType = "RANGE" //Sort key
                }
            },
                Projection = new Projection
                {
                    ProjectionType = "INCLUDE",
                    NonKeyAttributes = {
                    "Description", "Status"
                }
                }
            };

            // TitleIndex
            var titleIndex = new GlobalSecondaryIndex()
            {
                IndexName = "TitleIndex",
                ProvisionedThroughput = ptIndex,
                KeySchema = {
                new KeySchemaElement {
                    AttributeName = "Title", KeyType = "HASH" //Partition key
                },
                new KeySchemaElement {
                    AttributeName = "IssueId", KeyType = "RANGE" //Sort key
                }
            },
                Projection = new Projection
                {
                    ProjectionType = "KEYS_ONLY"
                }
            };

            // DueDateIndex
            var dueDateIndex = new GlobalSecondaryIndex()
            {
                IndexName = "DueDateIndex",
                ProvisionedThroughput = ptIndex,
                KeySchema = {
                new KeySchemaElement {
                    AttributeName = "DueDate",
                    KeyType = "HASH" //Partition key
                }
            },
                Projection = new Projection
                {
                    ProjectionType = "ALL"
                }
            };



            var createTableRequest = new CreateTableRequest
            {
                TableName = tableName,
                ProvisionedThroughput = new ProvisionedThroughput
                {
                    ReadCapacityUnits = (long)1,
                    WriteCapacityUnits = (long)1
                },
                AttributeDefinitions = attributeDefinitions,
                KeySchema = tableKeySchema,
                GlobalSecondaryIndexes = {
                createDateIndex, titleIndex, dueDateIndex
            }
            };

            Console.WriteLine("Creating table " + tableName + "...");
            client.CreateTable(createTableRequest);

            WaitUntilTableReady(tableName);
        }

        private static void LoadData()
        {
            Console.WriteLine("Loading data into table " + tableName + "...");

            // IssueId, Title,
            // Description,
            // CreateDate, LastUpdateDate, DueDate,
            // Priority, Status

            putItem("A-101", "Compilation error",
                "Can't compile Project X - bad version number. What does this mean?",
                "2013-11-01", "2013-11-02", "2013-11-10",
                1, "Assigned");

            putItem("A-102", "Can't read data file",
                "The main data file is missing, or the permissions are incorrect",
                "2013-11-01", "2013-11-04", "2013-11-30",
                2, "In progress");

            putItem("A-103", "Test failure",
                "Functional test of Project X produces errors",
                "2013-11-01", "2013-11-02", "2013-11-10",
                1, "In progress");

            putItem("A-104", "Compilation error",
                "Variable 'messageCount' was not initialized.",
                "2013-11-15", "2013-11-16", "2013-11-30",
                3, "Assigned");

            putItem("A-105", "Network issue",
                "Can't ping IP address 127.0.0.1. Please fix this.",
                "2013-11-15", "2013-11-16", "2013-11-19",
                5, "Assigned");
        }

        private static void putItem(
            String issueId, String title,
            String description,
            String createDate, String lastUpdateDate, String dueDate,
            Int32 priority, String status)
        {
            Dictionary<String, AttributeValue> item = new Dictionary<string, AttributeValue>();

            item.Add("IssueId", new AttributeValue
            {
                S = issueId
            });
            item.Add("Title", new AttributeValue
            {
                S = title
            });
            item.Add("Description", new AttributeValue
            {
                S = description
            });
            item.Add("CreateDate", new AttributeValue
            {
                S = createDate
            });
            item.Add("LastUpdateDate", new AttributeValue
            {
                S = lastUpdateDate
            });
            item.Add("DueDate", new AttributeValue
            {
                S = dueDate
            });
            item.Add("Priority", new AttributeValue
            {
                N = priority.ToString()
            });
            item.Add("Status", new AttributeValue
            {
                S = status
            });

            try
            {
                client.PutItem(new PutItemRequest
                {
                    TableName = tableName,
                    Item = item
                });
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        private static void QueryIndex(string indexName)
        {
            Console.WriteLine
                ("\n***********************************************************\n");
            Console.WriteLine("Querying index " + indexName + "...");

            QueryRequest queryRequest = new QueryRequest
            {
                TableName = tableName,
                IndexName = indexName,
                ScanIndexForward = true
            };


            String keyConditionExpression;
            Dictionary<string, AttributeValue> expressionAttributeValues = new Dictionary<string, AttributeValue>();

            if (indexName == "CreateDateIndex")
            {
                Console.WriteLine("Issues filed on 2013-11-01\n");

                keyConditionExpression = "CreateDate = :v_date and begins_with(IssueId, :v_issue)";
                expressionAttributeValues.Add(":v_date", new AttributeValue
                {
                    S = "2013-11-01"
                });
                expressionAttributeValues.Add(":v_issue", new AttributeValue
                {
                    S = "A-"
                });
            }
            else if (indexName == "TitleIndex")
            {
                Console.WriteLine("Compilation errors\n");

                keyConditionExpression = "Title = :v_title and begins_with(IssueId, :v_issue)";
                expressionAttributeValues.Add(":v_title", new AttributeValue
                {
                    S = "Compilation error"
                });
                expressionAttributeValues.Add(":v_issue", new AttributeValue
                {
                    S = "A-"
                });

                // Select
                queryRequest.Select = "ALL_PROJECTED_ATTRIBUTES";
            }
            else if (indexName == "DueDateIndex")
            {
                Console.WriteLine("Items that are due on 2013-11-30\n");

                keyConditionExpression = "DueDate = :v_date";
                expressionAttributeValues.Add(":v_date", new AttributeValue
                {
                    S = "2013-11-30"
                });

                // Select
                queryRequest.Select = "ALL_PROJECTED_ATTRIBUTES";
            }
            else
            {
                Console.WriteLine("\nNo valid index name provided");
                return;
            }

            queryRequest.KeyConditionExpression = keyConditionExpression;
            queryRequest.ExpressionAttributeValues = expressionAttributeValues;

            var result = client.Query(queryRequest);
            var items = result.Items;
            foreach (var currentItem in items)
            {
                foreach (string attr in currentItem.Keys)
                {
                    if (attr == "Priority")
                    {
                        Console.WriteLine(attr + "---> " + currentItem[attr].N);
                    }
                    else
                    {
                        Console.WriteLine(attr + "---> " + currentItem[attr].S);
                    }
                }
                Console.WriteLine();
            }
        }

        private static void DeleteTable(string tableName)
        {
            Console.WriteLine("Deleting table " + tableName + "...");
            client.DeleteTable(new DeleteTableRequest
            {
                TableName = tableName
            });
            WaitForTableToBeDeleted(tableName);
        }

        private static void WaitUntilTableReady(string tableName)
        {
            string status = null;
            // Let us wait until table is created. Call DescribeTable.
            do
            {
                System.Threading.Thread.Sleep(5000); // Wait 5 seconds.
                try
                {
                    var res = client.DescribeTable(new DescribeTableRequest
                    {
                        TableName = tableName
                    });

                    Console.WriteLine("Table name: {0}, status: {1}",
                              res.Table.TableName,
                              res.Table.TableStatus);
                    status = res.Table.TableStatus;
                }
                catch (ResourceNotFoundException)
                {
                    // DescribeTable is eventually consistent. So you might
                    // get resource not found. So we handle the potential exception.
                }
            } while (status != "ACTIVE");
        }

        private static void WaitForTableToBeDeleted(string tableName)
        {
            bool tablePresent = true;

            while (tablePresent)
            {
                System.Threading.Thread.Sleep(5000); // Wait 5 seconds.
                try
                {
                    var res = client.DescribeTable(new DescribeTableRequest
                    {
                        TableName = tableName
                    });

                    Console.WriteLine("Table name: {0}, status: {1}",
                              res.Table.TableName,
                              res.Table.TableStatus);
                }
                catch (ResourceNotFoundException)
                {
                    tablePresent = false;
                }
            }
        }
    }
}
```

# Bekerja dengan Indeks Sekunder Global di DynamoDB menggunakan AWS CLI
<a name="GCICli"></a>

Anda dapat menggunakan AWS CLI untuk membuat tabel Amazon DynamoDB dengan satu atau lebih indeks sekunder global, menjelaskan indeks pada tabel, dan melakukan kueri menggunakan indeks.

**Topics**
+ [Membuat tabel dengan Indeks Sekunder Global](#GCICli.CreateTableWithIndex)
+ [Menambahkan Indeks Sekunder Global ke tabel yang sudah ada](#GCICli.CreateIndexAfterTable)
+ [Mendeskripsikan tabel dengan Indeks Sekunder Global](#GCICli.DescribeTableWithIndex)
+ [Mengkueri Indeks Sekunder Global](#GCICli.QueryAnIndex)

## Membuat tabel dengan Indeks Sekunder Global
<a name="GCICli.CreateTableWithIndex"></a>

Indeks sekunder global dapat dibuat pada saat Anda membuat tabel. Untuk melakukannya, gunakan parameter `create-table` dan berikan spesifikasi Anda untuk satu atau beberapa indeks sekunder global. Contoh berikut membuat tabel bernama `GameScores` dengan indeks sekunder global yang disebut `GameTitleIndex`. Tabel dasar memiliki kunci partisi `UserId` dan kunci urutan `GameTitle`, sehingga Anda dapat menemukan skor terbaik pengguna individu untuk game tertentu secara efisien, sedangkan GSI memiliki kunci partisi `GameTitle` dan kunci urutan `TopScore`, memungkinkan Anda untuk cepat menemukan skor tertinggi secara keseluruhan untuk game tertentu.

```
aws dynamodb create-table \
    --table-name GameScores \
    --attribute-definitions AttributeName=UserId,AttributeType=S \
                            AttributeName=GameTitle,AttributeType=S \
                            AttributeName=TopScore,AttributeType=N  \
    --key-schema AttributeName=UserId,KeyType=HASH \
                 AttributeName=GameTitle,KeyType=RANGE \
    --provisioned-throughput ReadCapacityUnits=10,WriteCapacityUnits=5 \
    --global-secondary-indexes \
        "[
            {
                \"IndexName\": \"GameTitleIndex\",
                \"KeySchema\": [{\"AttributeName\":\"GameTitle\",\"KeyType\":\"HASH\"},
                                {\"AttributeName\":\"TopScore\",\"KeyType\":\"RANGE\"}],
                \"Projection\":{
                    \"ProjectionType\":\"INCLUDE\",
                    \"NonKeyAttributes\":[\"UserId\"]
                },
                \"ProvisionedThroughput\": {
                    \"ReadCapacityUnits\": 10,
                    \"WriteCapacityUnits\": 5
                }
            }
        ]"
```

Anda harus menunggu hingga DynamoDB membuat tabel dan menetapkan status tabel menjadi `ACTIVE`. Setelah itu, Anda bisa mulai memasukkan item data ke dalam tabel. Anda dapat menggunakan [describe-table](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/describe-table.html) untuk menentukan status pembuatan tabel.

## Menambahkan Indeks Sekunder Global ke tabel yang sudah ada
<a name="GCICli.CreateIndexAfterTable"></a>

Indeks sekunder global juga dapat ditambahkan atau diubah setelah pembuatan tabel. Untuk melakukannya, gunakan parameter `update-table` dan berikan spesifikasi Anda untuk satu atau beberapa indeks sekunder global. Contoh berikut menggunakan skema yang sama seperti contoh sebelumnya, tetapi mengasumsikan bahwa tabel telah dibuat dan GSI akan ditambahkan nanti.

```
aws dynamodb update-table \
    --table-name GameScores \
    --attribute-definitions AttributeName=TopScore,AttributeType=N  \
    --global-secondary-index-updates \
        "[
            {
                \"Create\": {
                    \"IndexName\": \"GameTitleIndex\",
                    \"KeySchema\": [{\"AttributeName\":\"GameTitle\",\"KeyType\":\"HASH\"},
                                    {\"AttributeName\":\"TopScore\",\"KeyType\":\"RANGE\"}],
                    \"Projection\":{
                        \"ProjectionType\":\"INCLUDE\",
                        \"NonKeyAttributes\":[\"UserId\"]
                    }
                }
            }
        ]"
```

## Mendeskripsikan tabel dengan Indeks Sekunder Global
<a name="GCICli.DescribeTableWithIndex"></a>

Untuk mendapatkan informasi tentang Indeks Sekunder Global pada sebuah tabel, gunakan parameter `describe-table`. Untuk setiap indeks, Anda dapat mengakses namanya, skema kunci, dan atribut yang diproyeksikan.

```
aws dynamodb describe-table --table-name GameScores
```

## Mengkueri Indeks Sekunder Global
<a name="GCICli.QueryAnIndex"></a>

Anda dapat menggunakan operasi `query` pada indeks sekunder global dengan cara yang hampir sama seperti Anda `query` tabel. Anda harus menentukan nama indeks, kriteria kueri untuk kunci urutan indeks, dan atribut yang ingin Anda kembalikan. Dalam contoh ini, indeks adalah `GameTitleIndex` dan kunci urutan indeks adalah `GameTitle`.

Satu-satunya atribut yang dikembalikan adalah atribut yang telah diproyeksikan ke dalam indeks. Anda dapat memodifikasi kueri ini untuk memilih atribut non-kunci juga, tetapi ini akan memerlukan aktivitas pengambilan tabel yang relatif mahal. Untuk informasi selengkapnya tentang pengambilan tabel, lihat [Proyeksi atribut](GSI.md#GSI.Projections).

```
aws dynamodb query --table-name GameScores\
    --index-name GameTitleIndex \
    --key-condition-expression "GameTitle = :v_game" \
    --expression-attribute-values '{":v_game":{"S":"Alien Adventure"} }'
```

# Indeks sekunder lokal
<a name="LSI"></a>

Beberapa aplikasi hanya perlu mengkueri data menggunakan kunci primer tabel dasar. Namun, mungkin ada situasi ketika kunci urutan alternatif akan berguna. Untuk memberi aplikasi Anda pilihan kunci urutan, Anda dapat membuat satu atau beberapa indeks sekunder lokal pada tabel Amazon DynamoDB dan mengeluarkan permintaan `Query` atau `Scan` terhadap indeks ini.

**Topics**
+ [Skenario: Menggunakan Indeks Sekunder Lokal](#LSI.Scenario)
+ [Proyeksi atribut](#LSI.Projections)
+ [Membuat Indeks Sekunder Lokal](#LSI.Creating)
+ [Membaca data dari Indeks Sekunder Lokal](#LSI.Reading)
+ [Penulisan item dan Indeks Sekunder Lokal](#LSI.Writes)
+ [Pertimbangan throughput yang disediakan untuk Indeks Sekunder Lokal](#LSI.ThroughputConsiderations)
+ [Pertimbangan penyimpanan untuk Indeks Sekunder Lokal](#LSI.StorageConsiderations)
+ [Kumpulan item dalam Indeks Sekunder Lokal](#LSI.ItemCollections)
+ [Menggunakan Indeks Sekunder Lokal: Java](LSIJavaDocumentAPI.md)
+ [Menggunakan Indeks Sekunder Lokal: .NET](LSILowLevelDotNet.md)
+ [Bekerja dengan Indeks Sekunder Lokal di DynamoDB AWS CLI](LCICli.md)

## Skenario: Menggunakan Indeks Sekunder Lokal
<a name="LSI.Scenario"></a>

Sebagai contoh, perhatikan `Thread` tabel. Tabel ini berguna untuk aplikasi seperti [forum diskusi AWS](https://forums.aws.amazon.com/). Diagram berikut menunjukkan bagaimana item dalam tabel akan diatur. (Tidak semua atribut ditampilkan.)

![\[Tabel utas yang berisi daftar nama forum, subjek, waktu posting terakhir, dan jumlah balasan.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/LSI_01.png)


DynamoDB menyimpan semua item dengan nilai kunci partisi yang sama secara berkelanjutan. Dalam contoh ini, dengan `ForumName` tertentu, operasi `Query` dapat segera menemukan semua utas untuk forum itu. Dalam grup item dengan nilai kunci partisi yang sama, item diurutkan berdasarkan nilai kunci urutan. Jika kunci urutan (`Subject`) juga disediakan dalam kueri, DynamoDB dapat mempersempit hasil yang dikembalikan—misalnya, mengembalikan semua utas di forum "S3" yang memiliki `Subject` yang diawali dengan huruf "a".

Beberapa permintaan mungkin memerlukan pola akses data yang lebih kompleks. Misalnya:
+ Utas forum mana yang paling banyak dilihat dan mendapatkan balasan?
+ Utas mana di forum tertentu yang memiliki jumlah pesan terbanyak?
+ Berapa banyak utas yang diposting di forum tertentu dalam jangka waktu tertentu?

Untuk menjawab pertanyaan-pertanyaan ini, tindakan `Query` tidak akan cukup. Sebaliknya, Anda harus `Scan` seluruh tabel. Untuk tabel dengan jutaan item, ini akan menghabiskan banyak throughput baca yang disediakan dan membutuhkan waktu lama untuk selesai.

Namun, Anda dapat menentukan satu atau beberapa indeks sekunder lokal pada atribut non-kunci, seperti `Replies` atau `LastPostDateTime`.

*Indeks sekunder lokal* mempertahankan kunci urutan alternatif untuk nilai kunci partisi yang diberikan. Indeks sekunder lokal juga berisi salinan beberapa atau semua atribut dari tabel dasarnya. Anda akan menentukan atribut yang diproyeksikan ke indeks sekunder lokal saat membuat tabel. Data dalam indeks sekunder lokal diatur oleh kunci partisi yang sama dengan tabel dasar, tetapi dengan kunci urutan yang berbeda. Ini memungkinkan Anda mengakses item data secara efisien di seluruh dimensi yang berbeda ini. Untuk fleksibilitas kueri atau pemindaian yang lebih baik, Anda dapat membuat hingga lima indeks sekunder lokal per tabel. 

Misalkan sebuah aplikasi perlu menemukan semua utas yang telah diposting dalam tiga bulan terakhir di forum tertentu. Tanpa indeks sekunder lokal, aplikasi harus `Scan` seluruh tabel `Thread` dan membuang postingan apa pun yang tidak berada dalam periode waktu yang ditentukan. Dengan indeks sekunder lokal, operasi `Query` dapat menggunakan `LastPostDateTime` sebagai kunci urutan dan menemukan data dengan cepat.

Diagram berikut menunjukkan indeks sekunder lokal bernama `LastPostIndex`. Perhatikan bahwa kunci partisi sama dengan tabel `Thread`, tetapi kunci urutannya adalah `LastPostDateTime`.

![\[LastPostIndex tabel yang berisi daftar nama forum, subjek, dan waktu posting terakhir.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/LSI_02.png)


Setiap indeks sekunder lokal harus memenuhi syarat berikut:
+ Kunci partisi sama dengan tabel dasarnya.
+ Kunci urutan terdiri dari satu atribut skalar.
+ Kunci urutan tabel dasar diproyeksikan ke dalam indeks, tempat kunci tersebut berfungsi sebagai atribut non-kunci.

Dalam contoh ini, kunci partisi adalah `ForumName` dan kunci urutan indeks sekunder lokal adalah `LastPostDateTime`. Selain itu, nilai kunci urutan dari tabel dasar (dalam contoh ini, `Subject`) diproyeksikan ke dalam indeks, tetapi bukan merupakan bagian dari kunci indeks. Jika aplikasi membutuhkan daftar yang didasarkan pada `ForumName` dan `LastPostDateTime`, aplikasi dapat mengeluarkan permintaan `Query` terhadap `LastPostIndex`. Hasil kueri diurutkan menurut `LastPostDateTime`, dan dapat dikembalikan dalam urutan menaik atau menurun. Kueri juga dapat menerapkan syarat kunci, seperti hanya mengembalikan item yang memiliki `LastPostDateTime` dalam rentang waktu tertentu.

Setiap indeks sekunder lokal otomatis berisi kunci partisi dan kunci urutan dari tabel dasarnya; Anda secara opsional dapat memproyeksikan atribut non-kunci ke dalam indeks. Saat Anda mengkueri indeks, DynamoDB dapat mengambil atribut yang diproyeksikan ini secara efisien. Saat Anda mengkueri indeks sekunder lokal, kueri juga dapat mengambil atribut yang *tidak* diproyeksikan ke dalam indeks. DynamoDB otomatis mengambil atribut ini dari tabel dasar, tetapi dengan latensi lebih besar dan dengan biaya throughput yang disediakan lebih tinggi.

Untuk indeks sekunder lokal apa pun, Anda dapat menyimpan hingga 10 GB data per nilai kunci partisi yang berbeda. Angka ini mencakup semua item dalam tabel dasar, ditambah semua item dalam indeks, yang memiliki nilai kunci partisi yang sama. Untuk informasi selengkapnya, lihat [Kumpulan item dalam Indeks Sekunder Lokal](#LSI.ItemCollections).

## Proyeksi atribut
<a name="LSI.Projections"></a>

Dengan `LastPostIndex`, sebuah aplikasi dapat menggunakan `ForumName` dan `LastPostDateTime` sebagai kriteria kueri. Namun, untuk mengambil atribut tambahan apa pun, DynamoDB harus melakukan operasi baca tambahan terhadap tabel `Thread`. Pembacaan tambahan ini dikenal sebagai *pengambilan*, dan pembacaan tersebut dapat meningkatkan jumlah total throughput yang disediakan yang diperlukan untuk kueri.

Misalkan Anda ingin mengisi halaman web dengan daftar semua utas di “S3" dan jumlah balasan untuk setiap utas, diurutkan berdasarkan balasan terakhir yang date/time dimulai dengan balasan terbaru. Untuk mengisi daftar ini, Anda memerlukan atribut berikut:
+ `Subject`
+ `Replies`
+ `LastPostDateTime`

Cara paling efisien untuk mengkueri data ini dan untuk menghindari operasi pengambilan adalah dengan memproyeksikan atribut `Replies` dari tabel ke dalam indeks sekunder lokal, seperti yang ditunjukkan dalam diagram ini.

![\[LastPostIndex tabel yang berisi daftar nama forum, waktu posting terakhir, subjek, dan balasan.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/LSI_03.png)




*Proyeksi* adalah kumpulan atribut yang disalin dari tabel ke indeks sekunder. Kunci partisi dan kunci urutan tabel selalu diproyeksikan ke dalam indeks; Anda dapat memproyeksikan atribut lain untuk mendukung persyaratan kueri aplikasi Anda. Saat Anda mengkueri indeks, Amazon DynamoDB dapat mengakses atribut apa pun dalam proyeksi seolah-olah atribut tersebut berada dalam tabelnya sendiri.

Saat membuat indeks sekunder, Anda perlu menentukan atribut yang akan diproyeksikan ke dalam indeks. DynamoDB menyediakan tiga opsi berbeda untuk ini:
+ *KEYS\$1ONLY* – Setiap item dalam indeks hanya terdiri dari kunci partisi tabel dan nilai kunci urutan, ditambah nilai kunci indeks. Opsi `KEYS_ONLY` menghasilkan indeks sekunder sekecil mungkin.
+ *INCLUDE* – Selain atribut yang dijelaskan dalam `KEYS_ONLY`, indeks sekunder akan menyertakan atribut non-kunci lain yang Anda tentukan.
+ *ALL* – Indeks sekunder menyertakan semua atribut dari tabel sumber. Karena semua data tabel diduplikasi dalam indeks, proyeksi `ALL` menghasilkan indeks sekunder sebesar yang mungkin.

Pada diagram sebelumnya, atribut non-kunci `Replies` diproyeksikan ke dalam `LastPostIndex`. Aplikasi dapat meminta `LastPostIndex` sebagai ganti dari tabel `Thread` lengkap untuk mengisi halaman web dengan `Subject`, `Replies`, dan `LastPostDateTime`. Jika ada atribut non-kunci lain yang diminta, DynamoDB perlu mengambil atribut tersebut dari tabel `Thread`. 

Dari sudut pandang aplikasi, pengambilan atribut tambahan dari tabel dasar dilakukan secara otomatis dan transparan, jadi tidak perlu menulis ulang logika aplikasi apa pun. Namun, pengambilan tersebut dapat sangat mengurangi keuntungan performa menggunakan indeks sekunder lokal.

Saat memilih atribut untuk diproyeksikan ke dalam indeks sekunder lokal, Anda harus mempertimbangkan tradeoff antara biaya throughput yang disediakan dan biaya penyimpanan:
+ Jika Anda hanya perlu mengakses beberapa atribut dengan latensi serendah mungkin, pertimbangkan untuk hanya memproyeksikan atribut tersebut ke dalam indeks sekunder lokal. Semakin kecil indeks, semakin sedikit biaya penyimpanannya, dan semakin sedikit pula biaya tulis Anda. Jika ada atribut yang terkadang perlu Anda ambil, biaya untuk throughput yang disediakan mungkin lebih besar daripada biaya jangka panjang untuk menyimpan atribut tersebut.
+ Jika aplikasi Anda sering mengakses beberapa atribut non-kunci, sebaiknya Anda memproyeksikan atribut tersebut ke dalam indeks sekunder lokal. Biaya penyimpanan tambahan untuk indeks sekunder lokal mengimbangi biaya melakukan pemindaian tabel yang sering dilakukan.
+ Jika sering mengakses sebagian besar atribut non-kunci, Anda dapat memproyeksikan atribut ini—atau bahkan seluruh tabel dasar— ke dalam indeks sekunder lokal. Ini memberi Anda fleksibilitas maksimum dan penggunaan persediaan throughput terendah, karena pengambilan tidak diperlukan. Namun, biaya penyimpanan Anda akan meningkat, atau bahkan dua kali lipat jika Anda memproyeksikan semua atribut.
+ Jika aplikasi Anda jarang mengkueri tabel, tetapi harus melakukan banyak penulisan atau pembaruan terhadap data dalam tabel, pertimbangkan untuk memproyeksikan *KEYS\$1ONLY*. Indeks sekunder lokal akan berukuran minimal, tetapi akan tetap tersedia jika diperlukan untuk aktivitas kueri. 

## Membuat Indeks Sekunder Lokal
<a name="LSI.Creating"></a>

Untuk membuat satu atau beberapa indeks sekunder lokal pada tabel, gunakan parameter `LocalSecondaryIndexes` operasi `CreateTable`. Indeks sekunder lokal pada tabel dibuat saat tabel dibuat. Saat Anda menghapus tabel, indeks sekunder lokal apa pun di tabel itu juga akan dihapus.

Anda harus menentukan satu atribut non-kunci untuk berfungsi sebagai kunci urutan indeks sekunder lokal. Atribut yang Anda pilih harus berupa skalar `String`, `Number`, atau `Binary`. Jenis skalar, jenis dokumen, dan jenis kumpulan lain tidak diperbolehkan. Untuk daftar lengkap jenis data, lihat [Jenis Data](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes).

**penting**  
Untuk tabel dengan indeks sekunder lokal, ada batas ukuran 10 GB per nilai kunci partisi. Tabel dengan indeks sekunder lokal dapat menyimpan berapa pun jumlah item, asalkan ukuran total untuk nilai kunci satu partisi tidak melebihi 10 GB. Untuk informasi selengkapnya, lihat [Batas ukuran kumpulan item](#LSI.ItemCollections.SizeLimit).

Anda dapat memproyeksikan atribut jenis data apa pun ke dalam indeks sekunder lokal. Ini termasuk skalar, dokumen, dan kumpulan. Untuk daftar lengkap jenis data, lihat [Jenis Data](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes).

## Membaca data dari Indeks Sekunder Lokal
<a name="LSI.Reading"></a>

Anda dapat mengambil item dari indeks sekunder lokal menggunakan operasi `Query` dan `Scan`. Operasi `GetItem` dan `BatchGetItem` tidak dapat digunakan pada indeks sekunder lokal.

### Mengkueri Indeks Sekunder Lokal
<a name="LSI.Querying"></a>

Dalam tabel DynamoDB, nilai kunci partisi gabungan dan nilai kunci urutan untuk setiap item harus unik. Namun, dalam indeks sekunder lokal, nilai kunci urutan tidak perlu unik untuk nilai kunci partisi yang diberikan. Jika ada beberapa item dalam indeks sekunder lokal yang memiliki nilai kunci urutan yang sama, operasi `Query` mengembalikan semua item yang memiliki nilai kunci partisi yang sama. Sebagai respons, item yang cocok tidak dikembalikan dalam urutan tertentu.

Anda dapat mengkueri indeks sekunder lokal menggunakan bacaan akhir konsisten atau bacaan sangat konsisten. Untuk menentukan jenis konsistensi yang Anda inginkan, gunakan parameter `ConsistentRead` operasi `Query`. Bacaan sangat konsisten dari indeks sekunder lokal selalu mengembalikan nilai terbaru yang diperbarui. Jika kueri perlu mengambil atribut tambahan dari tabel dasar, atribut tersebut akan konsisten dengan indeks.

**Example**  
Pertimbangkan data berikut yang dikembalikan dari `Query` yang meminta data dari utas diskusi di forum tertentu.  

```
{
    "TableName": "Thread",
    "IndexName": "LastPostIndex",
    "ConsistentRead": false,
    "ProjectionExpression": "Subject, LastPostDateTime, Replies, Tags",
    "KeyConditionExpression": 
        "ForumName = :v_forum and LastPostDateTime between :v_start and :v_end",
    "ExpressionAttributeValues": {
        ":v_start": {"S": "2015-08-31T00:00:00.000Z"},
        ":v_end": {"S": "2015-11-31T00:00:00.000Z"},
        ":v_forum": {"S": "EC2"}
    }
}
```
Dalam kueri ini:  
+ DynamoDB mengakses `LastPostIndex`, menggunakan kunci partisi `ForumName` untuk menemukan item indeks untuk "EC2". Semua item indeks dengan kunci ini disimpan berdekatan satu sama lain untuk pengambilan cepat.
+ Dalam forum ini, DynamoDB menggunakan indeks untuk mencari kunci yang cocok dengan syarat `LastPostDateTime` yang ditentukan.
+ Karena atribut `Replies` diproyeksikan ke dalam indeks, DynamoDB dapat mengambil atribut ini tanpa menggunakan throughput tambahan yang disediakan.
+ Atribut `Tags` tidak diproyeksikan ke dalam indeks, jadi DynamoDB harus mengakses tabel `Thread` dan mengambil atribut ini.
+ Hasilnya ditampilkan, diurutkan berdasarkan `LastPostDateTime`. Entri indeks diurutkan menurut nilai kunci partisi dan kemudian menurut nilai kunci urutan, dan `Query` mengembalikannya sesuai urutan penyimpanannya. (Anda dapat menggunakan parameter `ScanIndexForward` untuk mengembalikan hasil dalam urutan menurun.)
Karena atribut `Tags` tidak diproyeksikan ke indeks sekunder lokal, DynamoDB harus menggunakan unit kapasitas baca tambahan untuk mengambil atribut ini dari tabel dasar. Jika sering menjalankan kueri ini, Anda harus memproyeksikan `Tags` ke `LastPostIndex` untuk menghindari pengambilan dari tabel dasar. Namun, jika Anda hanya perlu mengakses `Tags` sesekali, biaya penyimpanan tambahan untuk memproyeksikan `Tags` ke dalam indeks mungkin tidak bermanfaat.

### Memindai Indeks Sekunder Lokal
<a name="LSI.Scanning"></a>

Anda dapat menggunakan `Scan` untuk mengambil semua data dari indeks sekunder lokal. Anda harus memberikan nama tabel dasar dan nama indeks dalam permintaan. Dengan `Scan`, DynamoDB membaca semua data dalam indeks dan mengembalikannya ke aplikasi. Anda juga dapat meminta agar hanya sebagian data yang dikembalikan, dan data yang tersisa harus dibuang. Untuk melakukannya, gunakan parameter `FilterExpression` API `Scan`. Untuk informasi selengkapnya, lihat [Ekspresi filter untuk pemindaian](Scan.md#Scan.FilterExpression).

## Penulisan item dan Indeks Sekunder Lokal
<a name="LSI.Writes"></a>

DynamoDB otomatis membuat semua indeks sekunder lokal tersinkronisasi dengan tabel dasar masing-masing. Aplikasi tidak pernah menulis langsung ke indeks. Namun, Anda harus memahami implikasi dari cara DynamoDB mempertahankan indeks ini.

Saat membuat indeks sekunder lokal, Anda menentukan atribut untuk dijadikan sebagai kunci urutan untuk indeks. Anda juga menentukan jenis data untuk atribut tersebut. Artinya, setiap kali Anda menulis item ke tabel dasar, jika item tersebut mendefinisikan atribut kunci indeks, jenisnya harus cocok dengan jenis data skema kunci indeks. Dalam kasus `LastPostIndex`, kunci urutan `LastPostDateTime` dalam indeks didefinisikan sebagai jenis data `String`. Jika Anda mencoba menambahkan item ke tabel `Thread` dan menentukan jenis data yang berbeda untuk `LastPostDateTime` (seperti `Number`), DynamoDB mengembalikan `ValidationException` karena jenis data tidak cocok.

Tidak ada persyaratan untuk one-to-one hubungan antara item dalam tabel dasar dan item dalam indeks sekunder lokal. Bahkan, perilaku ini dapat menguntungkan untuk banyak aplikasi. 

Tabel dengan banyak indeks sekunder lokal menimbulkan biaya lebih tinggi untuk aktivitas tulis dibandingkan tabel dengan lebih sedikit indeks. Untuk informasi selengkapnya, lihat [Pertimbangan throughput yang disediakan untuk Indeks Sekunder Lokal](#LSI.ThroughputConsiderations).

**penting**  
Untuk tabel dengan indeks sekunder lokal, ada batas ukuran 10 GB per nilai kunci partisi. Tabel dengan indeks sekunder lokal dapat menyimpan berapa pun jumlah item, asalkan ukuran total untuk nilai kunci satu partisi tidak melebihi 10 GB. Untuk informasi selengkapnya, lihat [Batas ukuran kumpulan item](#LSI.ItemCollections.SizeLimit).

## Pertimbangan throughput yang disediakan untuk Indeks Sekunder Lokal
<a name="LSI.ThroughputConsiderations"></a>

Saat membuat tabel di DynamoDB, Anda menyediakan unit kapasitas baca dan tulis untuk beban kerja tabel yang diharapkan. Beban kerja tersebut mencakup aktivitas baca dan tulis pada indeks sekunder lokal tabel.

Untuk melihat tarif saat ini untuk kapasitas throughput yang disediakan, lihat [Harga Amazon DynamoDB](https://aws.amazon.com/dynamodb/pricing).

### Unit kapasitas baca
<a name="LSI.ThroughputConsiderations.Reads"></a>

Saat Anda mengkueri indeks sekunder lokal, jumlah unit kapasitas baca yang digunakan bergantung pada cara data diakses.

Seperti kueri tabel, kueri indeks dapat menggunakan bacaan akhir konsisten atau bacaan sangat konsisten, tergantung pada nilai `ConsistentRead`. Satu bacaan sangat konsisten menghabiskan satu unit kapasitas baca; bacaan akhir konsisten hanya menghabiskan setengahnya. Jadi, dengan memilih bacaan akhir konsisten, Anda dapat mengurangi biaya unit kapasitas baca Anda.

Untuk kueri indeks yang hanya meminta kunci indeks dan atribut yang diproyeksikan, DynamoDB menghitung aktivitas baca yang disediakan dengan cara yang sama seperti kueri terhadap tabel. Satu-satunya hal yang membedakan adalah penghitungan didasarkan pada ukuran entri indeks, bukan ukuran item dalam tabel dasar. Jumlah unit kapasitas baca adalah jumlah dari semua ukuran atribut yang diproyeksikan di semua item yang dikembalikan; hasilnya kemudian dibulatkan ke batas 4 KB berikutnya. Untuk informasi selengkapnya tentang cara DynamoDB menghitung penggunaan throughput yang disediakan, lihat [DynamoDB menyediakan mode kapasitas](provisioned-capacity-mode.md).

Untuk kueri indeks yang membaca atribut yang tidak diproyeksikan ke indeks sekunder lokal, DynamoDB perlu mengambil atribut tersebut dari tabel dasar, selain membaca atribut yang diproyeksikan dari indeks. Pengambilan ini terjadi saat Anda menyertakan atribut yang tidak diproyeksikan dalam parameter `Select` atau `ProjectionExpression` operasi `Query`. Pengambilan menyebabkan latensi tambahan dalam respons kueri, dan juga menimbulkan biaya throughput yang disediakan lebih tinggi: Selain pembacaan dari indeks sekunder lokal yang dijelaskan sebelumnya, Anda dikenakan biaya untuk unit kapasitas baca untuk setiap item tabel dasar yang diambil. Biaya ini untuk pembacaan setiap item dari tabel, bukan hanya atribut yang diminta.

Ukuran maksimum hasil yang dikembalikan oleh operasi `Query` adalah 1 MB. Ini termasuk ukuran semua nama dan nilai atribut di semua item yang dikembalikan. Namun, jika Kueri terhadap indeks sekunder lokal menyebabkan DynamoDB mengambil atribut item dari tabel dasar, ukuran maksimum data dalam hasil mungkin lebih rendah. Dalam hal ini, ukuran hasil adalah jumlah dari:
+ Ukuran item yang cocok dalam indeks, dibulatkan ke atas hingga 4 KB berikutnya.
+ Ukuran setiap item yang cocok di tabel dasar, dengan setiap item dibulatkan satu per satu ke 4 KB berikutnya.

Menggunakan rumus ini, ukuran maksimum hasil yang dikembalikan oleh operasi Kueri masih 1 MB.

Misalnya, pertimbangkan tabel tempat ukuran setiap item adalah 300 byte. Ada indeks sekunder lokal di tabel itu, tetapi hanya 200 byte dari setiap item yang diproyeksikan ke dalam indeks. Sekarang anggaplah Anda `Query` indeks ini, bahwa kueri memerlukan pengambilan tabel untuk setiap item, dan kueri mengembalikan 4 item. DynamoDB merangkum berikut ini:
+ Ukuran item yang cocok dalam indeks: 200 byte × 4 item = 800 byte; ini kemudian dibulatkan menjadi 4 KB.
+ Ukuran setiap item yang cocok di tabel dasar: (300 byte, dibulatkan hingga 4 KB) × 4 item = 16 KB.

Oleh karena itu, ukuran total data dalam hasil adalah 20 KB.

### Unit kapasitas tulis
<a name="LSI.ThroughputConsiderations.Writes"></a>

Saat item dalam tabel ditambahkan, diperbarui, atau dihapus, memperbarui indeks sekunder lokal akan menggunakan unit kapasitas tulis yang disediakan untuk tabel tersebut. Total biaya throughput yang disediakan untuk penulisan adalah jumlah unit kapasitas tulis yang digunakan dengan menulis ke tabel dan yang digunakan dengan memperbarui indeks sekunder lokal.

Biaya tulis item ke indeks sekunder lokal tergantung pada beberapa faktor:
+ Jika Anda menulis item baru ke tabel yang menentukan atribut yang diindeks, atau Anda memperbarui item yang ada untuk menentukan atribut terindeks yang sebelumnya tidak ditentukan, satu operasi tulis diperlukan untuk memasukkan item ke dalam indeks.
+ Jika pembaruan pada tabel mengubah nilai atribut kunci yang diindeks (dari A menjadi B), diperlukan dua penulisan: satu untuk menghapus item sebelumnya dari indeks dan satu lagi untuk memasukkan item baru ke dalam indeks.  
+ Jika suatu item ada dalam indeks, tetapi penulisan ke tabel menyebabkan atribut yang diindeks terhapus, satu penulisan diperlukan untuk menghapus proyeksi item lama dari indeks.
+ Jika item tidak ada dalam indeks sebelum atau setelah item diperbarui, tidak ada biaya penulisan tambahan untuk indeks tersebut.

Semua faktor ini mengasumsikan bahwa ukuran setiap item dalam indeks kurang dari atau sama dengan ukuran item 1 KB untuk menghitung unit kapasitas tulis. Entri indeks yang lebih besar memerlukan unit kapasitas tulis tambahan. Anda dapat meminimalkan biaya penulisan dengan mempertimbangkan atribut yang perlu dikembalikan oleh kueri dan hanya memproyeksikan atribut tersebut ke dalam indeks.

## Pertimbangan penyimpanan untuk Indeks Sekunder Lokal
<a name="LSI.StorageConsiderations"></a>

Saat aplikasi menulis item ke tabel, DynamoDB otomatis menyalin subset atribut yang benar ke indeks sekunder lokal tempat atribut tersebut akan muncul. AWS Akun Anda dikenakan biaya untuk penyimpanan item di tabel dasar dan juga untuk penyimpanan atribut dalam indeks sekunder lokal apa pun di tabel itu.

Jumlah ruang yang digunakan oleh item indeks adalah jumlah dari berikut ini:
+ Ukuran kunci primer tabel dasar dalam byte (kunci partisi dan kunci urutan)
+ Ukuran atribut kunci indeks dalam byte
+ Ukuran atribut yang diproyeksikan dalam byte (jika ada)
+ 100 byte dari overhead per item indeks

Untuk memperkirakan kebutuhan penyimpanan indeks sekunder lokal, Anda dapat memperkirakan ukuran rata-rata item dalam indeks lalu mengalikannya dengan jumlah item di index.

Jika tabel berisi item dengan atribut tertentu tidak ditentukan, tetapi atribut tersebut didefinisikan sebagai kunci urutan indeks, maka DynamoDB tidak menulis data apa pun untuk item tersebut ke indeks. 

## Kumpulan item dalam Indeks Sekunder Lokal
<a name="LSI.ItemCollections"></a>

**catatan**  
Bagian ini hanya berkaitan dengan tabel yang memiliki indeks sekunder lokal.

Di DynamoDB, *kumpulan item* adalah grup item yang memiliki nilai kunci partisi yang sama dalam tabel dan semua indeks sekunder lokalnya. Dalam contoh yang digunakan di seluruh bagian ini, kunci partisi untuk tabel `Thread` adalah `ForumName`, dan kunci partisi untuk `LastPostIndex` juga `ForumName`. Semua item tabel dan indeks dengan `ForumName` yang sama adalah bagian dari kumpulan item yang sama. Misalnya, di tabel `Thread` dan indeks sekunder lokal `LastPostIndex`, terdapat kumpulan item untuk forum `EC2` dan kumpulan item yang berbeda untuk forum `RDS`.

Diagram berikut menunjukkan kumpulan item untuk forum `S3`.

![\[Koleksi item DynamoDB dengan tabel dan item Indeks Sekunder Lokal yang memiliki nilai kunci partisi yang sama. S3\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/LSI_04.png)


Dalam diagram ini, kumpulan item terdiri dari semua item di `Thread` dan `LastPostIndex` dengan nilai kunci partisi `ForumName`-nya adalah "S3". Jika terdapat indeks sekunder lokal lainnya di tabel, item apa pun dalam indeks tersebut dengan `ForumName` yang sama dengan "S3" juga akan menjadi bagian dari kumpulan item.

Anda dapat menggunakan salah satu operasi berikut di DynamoDB untuk menampilkan informasi tentang kumpulan item:
+ `BatchWriteItem`
+ `DeleteItem`
+ `PutItem`
+ `UpdateItem`
+ `TransactWriteItems`

Masing-masing operasi ini mendukung parameter `ReturnItemCollectionMetrics`. Jika mengatur parameter ini ke `SIZE`, Anda dapat melihat informasi tentang ukuran setiap kumpulan item dalam indeks.

**Example**  
Berikut ini adalah contoh dari output operasi `UpdateItem` pada tabel `Thread`, dengan `ReturnItemCollectionMetrics` diatur ke `SIZE`. Item yang diperbarui memiliki nilai `ForumName` "EC2", jadi outputnya mencakup informasi tentang kumpulan item tersebut.  

```
{
    ItemCollectionMetrics: {
        ItemCollectionKey: {
            ForumName: "EC2"
        },
        SizeEstimateRangeGB: [0.0, 1.0]
    }
}
```
Objek `SizeEstimateRangeGB` menunjukkan bahwa ukuran kumpulan item ini antara 0 dan 1 GB. DynamoDB memperbarui perkiraan ukuran ini secara berkala, sehingga jumlahnya mungkin berbeda saat item diubah lagi.

### Batas ukuran kumpulan item
<a name="LSI.ItemCollections.SizeLimit"></a>

Ukuran maksimum kumpulan item apa pun untuk tabel yang memiliki satu atau beberapa indeks sekunder lokal adalah 10 GB. Ini tidak berlaku untuk kumpulan item dalam tabel tanpa indeks sekunder lokal, dan juga tidak berlaku untuk kumpulan item dalam indeks sekunder global. Hanya tabel yang memiliki satu atau beberapa indeks sekunder lokal yang terpengaruh.

Jika koleksi item melebihi batas 10 GB, DynamoDB dapat mengembalikan`ItemCollectionSizeLimitExceededException`, dan Anda mungkin tidak dapat menambahkan lebih banyak item ke koleksi item atau menambah ukuran item yang ada dalam koleksi item. (Operasi baca dan tulis yang mengecilkan ukuran kumpulan item masih diperbolehkan.) Anda masih dapat menambahkan item ke kumpulan item lain.

Untuk mengurangi ukuran kumpulan item, Anda dapat melakukan salah satu berikut ini:
+ Hapus item yang tidak diperlukan dengan nilai kunci partisi terkait. Jika Anda menghapus item ini dari tabel dasar, DynamoDB juga menghapus entri indeks yang memiliki nilai kunci partisi yang sama.
+ Perbarui item dengan menghapus atribut atau dengan mengurangi ukuran atribut. Jika atribut ini diproyeksikan ke indeks sekunder lokal, DynamoDB juga mengurangi ukuran entri indeks terkait.
+ Buat tabel baru dengan kunci partisi dan kunci urutan yang sama, lalu pindahkan item dari tabel lama ke tabel baru. Ini mungkin merupakan pendekatan yang tepat jika tabel memiliki data historis yang jarang diakses. Anda juga dapat mempertimbangkan untuk mengarsipkan data historis ini ke Amazon Simple Storage Service (Amazon S3).

Ketika ukuran total kumpulan item turun di bawah 10 GB, Anda dapat menambahkan item dengan nilai kunci partisi yang sama sekali lagi.

Sebagai praktik terbaik, sebaiknya Anda melengkapi aplikasi Anda untuk memantau ukuran kumpulan item Anda. Salah satu cara untuk melakukannya adalah dengan mengatur parameter `ReturnItemCollectionMetrics` ke `SIZE` setiap kali Anda menggunakan `BatchWriteItem`, `DeleteItem`, `PutItem`, atau `UpdateItem`. Aplikasi Anda akan memeriksa objek `ReturnItemCollectionMetrics` di output dan mencatat pesan kesalahan setiap kali kumpulan item melebihi batas yang ditentukan pengguna (8 GB, misalnya). Menetapkan batas kurang dari 10 GB akan memberi sistem peringatan dini sehingga Anda mengetahui bahwa kumpulan item mendekati batas, dan Anda dapat melakukan tindakan terhadap hal tersebut.

### Kumpulan dan partisi item
<a name="LSI.ItemCollections.OnePartition"></a>

Di tabel dengan satu atau beberapa indeks sekunder lokal, masing-masing kumpulan item disimpan dalam satu partisi. Ukuran total kumpulan item tersebut terbatas pada kemampuan partisi itu: 10 GB. Untuk aplikasi yang model datanya menyertakan kumpulan item yang ukurannya tidak dibatasi, atau jika Anda memperkirakan beberapa kumpulan item akan bertambah melebihi 10 GB di masa mendatang, Anda sebaiknya mempertimbangkan untuk menggunakan indeks sekunder global.

Anda harus merancang aplikasi Anda sehingga data tabel didistribusikan secara merata ke seluruh nilai kunci partisi yang berbeda. Untuk tabel dengan indeks sekunder lokal, aplikasi Anda tidak boleh membuat "hot spot" aktivitas baca dan tulis dalam satu kumpulan item pada satu partisi. 

# Menggunakan Indeks Sekunder Lokal: Java
<a name="LSIJavaDocumentAPI"></a>

Anda dapat menggunakan AWS SDK untuk Java Document API untuk membuat tabel Amazon DynamoDB dengan satu atau beberapa indeks sekunder lokal, menjelaskan indeks pada tabel, dan melakukan kueri menggunakan indeks.

Berikut ini adalah langkah-langkah umum untuk operasi tabel menggunakan AWS SDK untuk Java Document API.

1. Buat instans dari kelas `DynamoDB`.

1. Berikan parameter wajib dan opsional untuk operasi dengan membuat objek permintaan yang sesuai. 

1. Panggil metode sesuai yang ditentukan oleh klien yang Anda buat pada langkah sebelumnya. 

**Topics**
+ [Membuat tabel dengan Indeks Sekunder Lokal](#LSIJavaDocumentAPI.CreateTableWithIndex)
+ [Mendeskripsikan tabel dengan Indeks Sekunder Lokal](#LSIJavaDocumentAPI.DescribeTableWithIndex)
+ [Mengkueri Indeks Sekunder Lokal](#LSIJavaDocumentAPI.QueryAnIndex)
+ [Contoh: Indeks Sekunder Lokal menggunakan API dokumen Java](LSIJavaDocumentAPI.Example.md)

## Membuat tabel dengan Indeks Sekunder Lokal
<a name="LSIJavaDocumentAPI.CreateTableWithIndex"></a>

Indeks sekunder lokal harus dibuat pada saat Anda membuat tabel. Untuk melakukannya, gunakan metode `createTable` dan berikan spesifikasi Anda untuk satu atau beberapa indeks sekunder lokal. Contoh kode Java berikut membuat tabel untuk menyimpan informasi tentang lagu dalam koleksi musik. Kunci partisinya adalah `Artist` dan kunci urutannya adalah `SongTitle`. Indeks sekunder, `AlbumTitleIndex`, memfasilitasi kueri berdasarkan judul album. 

Berikut adalah langkah-langkah untuk membuat tabel dengan indeks sekunder lokal, menggunakan API dokumen DynamoDB. 

1. Buat instans dari kelas `DynamoDB`.

1. Buat instans dari kelas `CreateTableRequest` untuk memberikan informasi permintaan. 

   Anda harus memberikan nama tabel, kunci primernya, dan nilai throughput yang ditentukan. Untuk indeks sekunder lokal, Anda harus memberikan nama indeks, nama dan jenis data untuk kunci urutan indeks, skema kunci untuk indeks, dan proyeksi atribut.

1. Panggil metode `createTable` dengan menentukan objek permintaan sebagai parameter.

Contoh kode Java berikut mendemonstrasikan langkah sebelumnya. Kode ini membuat tabel (`Music`) dengan indeks sekunder pada atribut `AlbumTitle`. Kunci urutan dan kunci partisi tabel, ditambah kunci urutan indeks, adalah satu-satunya atribut yang diproyeksikan ke dalam indeks.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

String tableName = "Music";

CreateTableRequest createTableRequest = new CreateTableRequest().withTableName(tableName);

//ProvisionedThroughput
createTableRequest.setProvisionedThroughput(new ProvisionedThroughput().withReadCapacityUnits((long)5).withWriteCapacityUnits((long)5));

//AttributeDefinitions
ArrayList<AttributeDefinition> attributeDefinitions= new ArrayList<AttributeDefinition>();
attributeDefinitions.add(new AttributeDefinition().withAttributeName("Artist").withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition().withAttributeName("SongTitle").withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition().withAttributeName("AlbumTitle").withAttributeType("S"));

createTableRequest.setAttributeDefinitions(attributeDefinitions);

//KeySchema
ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>();
tableKeySchema.add(new KeySchemaElement().withAttributeName("Artist").withKeyType(KeyType.HASH));  //Partition key
tableKeySchema.add(new KeySchemaElement().withAttributeName("SongTitle").withKeyType(KeyType.RANGE));  //Sort key

createTableRequest.setKeySchema(tableKeySchema);

ArrayList<KeySchemaElement> indexKeySchema = new ArrayList<KeySchemaElement>();
indexKeySchema.add(new KeySchemaElement().withAttributeName("Artist").withKeyType(KeyType.HASH));  //Partition key
indexKeySchema.add(new KeySchemaElement().withAttributeName("AlbumTitle").withKeyType(KeyType.RANGE));  //Sort key

Projection projection = new Projection().withProjectionType(ProjectionType.INCLUDE);
ArrayList<String> nonKeyAttributes = new ArrayList<String>();
nonKeyAttributes.add("Genre");
nonKeyAttributes.add("Year");
projection.setNonKeyAttributes(nonKeyAttributes);

LocalSecondaryIndex localSecondaryIndex = new LocalSecondaryIndex()
    .withIndexName("AlbumTitleIndex").withKeySchema(indexKeySchema).withProjection(projection);

ArrayList<LocalSecondaryIndex> localSecondaryIndexes = new ArrayList<LocalSecondaryIndex>();
localSecondaryIndexes.add(localSecondaryIndex);
createTableRequest.setLocalSecondaryIndexes(localSecondaryIndexes);

Table table = dynamoDB.createTable(createTableRequest);
System.out.println(table.getDescription());
```

Anda harus menunggu hingga DynamoDB membuat tabel dan menetapkan status tabel menjadi `ACTIVE`. Setelah itu, Anda bisa mulai memasukkan item data ke dalam tabel.

## Mendeskripsikan tabel dengan Indeks Sekunder Lokal
<a name="LSIJavaDocumentAPI.DescribeTableWithIndex"></a>

Untuk mendapatkan informasi tentang indeks sekunder lokal pada tabel, gunakan metode `describeTable`. Untuk setiap indeks, Anda dapat mengakses namanya, skema kunci, dan atribut yang diproyeksikan.

Berikut ini adalah langkah-langkah untuk mengakses informasi indeks sekunder lokal suatu tabel menggunakan API Dokumen AWS SDK untuk Java .

1. Buat instans dari kelas `DynamoDB`.

1. Buat instans dari kelas `Table`. Anda harus memberikan nama tabel.

1. Panggil metode `describeTable` pada objek `Table`.

Contoh kode Java berikut mendemonstrasikan langkah sebelumnya.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

String tableName = "Music";

Table table = dynamoDB.getTable(tableName);

TableDescription tableDescription = table.describe();

List<LocalSecondaryIndexDescription> localSecondaryIndexes 
    = tableDescription.getLocalSecondaryIndexes();

// This code snippet will work for multiple indexes, even though
// there is only one index in this example.

Iterator<LocalSecondaryIndexDescription> lsiIter = localSecondaryIndexes.iterator();
while (lsiIter.hasNext()) {

    LocalSecondaryIndexDescription lsiDescription = lsiIter.next();
    System.out.println("Info for index " + lsiDescription.getIndexName() + ":");
    Iterator<KeySchemaElement> kseIter = lsiDescription.getKeySchema().iterator();
    while (kseIter.hasNext()) {
        KeySchemaElement kse = kseIter.next();
        System.out.printf("\t%s: %s\n", kse.getAttributeName(), kse.getKeyType());
    }
    Projection projection = lsiDescription.getProjection();
    System.out.println("\tThe projection type is: " + projection.getProjectionType());
    if (projection.getProjectionType().toString().equals("INCLUDE")) {
        System.out.println("\t\tThe non-key projected attributes are: " + projection.getNonKeyAttributes());
    }
}
```

## Mengkueri Indeks Sekunder Lokal
<a name="LSIJavaDocumentAPI.QueryAnIndex"></a>

Anda dapat menggunakan operasi `Query` pada indeks sekunder lokal dengan cara yang hampir sama seperti Anda `Query` tabel. Anda harus menentukan nama indeks, kriteria kueri untuk kunci urutan indeks, dan atribut yang ingin Anda kembalikan. Dalam contoh ini, indeks adalah `AlbumTitleIndex` dan kunci urutan indeks adalah `AlbumTitle`. 

Satu-satunya atribut yang dikembalikan adalah atribut yang telah diproyeksikan ke dalam indeks. Anda dapat memodifikasi kueri ini untuk memilih atribut non-kunci juga, tetapi ini akan memerlukan aktivitas pengambilan tabel yang relatif mahal. Untuk informasi selengkapnya tentang pengambilan tabel, lihat [Proyeksi atribut](LSI.md#LSI.Projections).

Berikut ini adalah langkah-langkah untuk query indeks sekunder lokal menggunakan AWS SDK untuk Java Document API. 

1. Buat instans dari kelas `DynamoDB`.

1. Buat instans dari kelas `Table`. Anda harus memberikan nama tabel.

1. Buat instans dari kelas `Index`. Anda harus memberikan nama indeks.

1. Panggil metode `query` dari kelas `Index`.

Contoh kode Java berikut mendemonstrasikan langkah sebelumnya.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

String tableName = "Music";

Table table = dynamoDB.getTable(tableName);
Index index = table.getIndex("AlbumTitleIndex");

QuerySpec spec = new QuerySpec()
    .withKeyConditionExpression("Artist = :v_artist and AlbumTitle = :v_title")
    .withValueMap(new ValueMap()
        .withString(":v_artist", "Acme Band")
        .withString(":v_title", "Songs About Life"));

ItemCollection<QueryOutcome> items = index.query(spec);

Iterator<Item> itemsIter = items.iterator();

while (itemsIter.hasNext()) {
    Item item = itemsIter.next();
    System.out.println(item.toJSONPretty());
}
```

### Bacaan yang konsisten pada Indeks Sekunder Lokal
<a name="LSIJavaDocumentAPI.ConsistentReads"></a>

Tidak seperti indeks sekunder global, yang hanya mendukung pembacaan yang konsisten pada akhirnya, indeks sekunder lokal mendukung pembacaan yang konsisten dan sangat konsisten. Bacaan sangat konsisten dari indeks sekunder lokal selalu mengembalikan nilai terbaru yang diperbarui. Jika kueri perlu mengambil atribut tambahan dari tabel dasar, atribut yang diambil tersebut juga konsisten sehubungan dengan indeks.

Secara default, `Query` menggunakan pembacaan yang konsisten pada akhirnya. Untuk meminta pembacaan yang sangat konsisten, atur `ConsistentRead` ke `true` dalam`QuerySpec`. Contoh kueri berikut `AlbumTitleIndex` menggunakan pembacaan yang sangat konsisten:

**Example**  

```
QuerySpec spec = new QuerySpec()
    .withKeyConditionExpression("Artist = :v_artist and AlbumTitle = :v_title")
    .withValueMap(new ValueMap()
        .withString(":v_artist", "Acme Band")
        .withString(":v_title", "Songs About Life"))
    .withConsistentRead(true);
```

**catatan**  
Pembacaan yang sangat konsisten mengkonsumsi satu unit kapasitas baca per 4 KB data yang dikembalikan (dibulatkan ke atas), sedangkan pembacaan yang konsisten pada akhirnya mengkonsumsi setengahnya. Misalnya, pembacaan yang sangat konsisten yang mengembalikan 9 KB data mengkonsumsi 3 unit kapasitas baca (9 KB/ 4 KB = 2,25, dibulatkan ke 3), sedangkan kueri yang sama menggunakan pembacaan yang konsisten pada akhirnya mengkonsumsi 1,5 unit kapasitas baca. Jika aplikasi Anda dapat mentolerir membaca data yang mungkin sedikit basi, gunakan pembacaan yang konsisten pada akhirnya untuk mengurangi penggunaan kapasitas baca Anda. Untuk informasi selengkapnya, lihat [Unit kapasitas baca](LSI.md#LSI.ThroughputConsiderations.Reads).

# Contoh: Indeks Sekunder Lokal menggunakan API dokumen Java
<a name="LSIJavaDocumentAPI.Example"></a>

Contoh kode Java berikut menunjukkan cara menggunakan indeks sekunder lokal di Amazon DynamoDB. Contoh membuat tabel bernama `CustomerOrders` dengan kunci partisi `CustomerId` dan kunci urutan `OrderId`. Ada dua indeks sekunder lokal di tabel ini:
+ `OrderCreationDateIndex` — Kunci urutannya adalah `OrderCreationDate`, dan atribut berikut diproyeksikan ke dalam indeks:
  + `ProductCategory`
  + `ProductName`
  + `OrderStatus`
  + `ShipmentTrackingId`
+ `IsOpenIndex` — Kunci urutannya adalah `IsOpen`, dan semua atribut tabel diproyeksikan ke dalam indeks.

Setelah tabel `CustomerOrders` dibuat, program memuat tabel dengan data yang mewakili pesanan pelanggan. Kemudian mengkueri data menggunakan indeks sekunder lokal. Terakhir, program menghapus tabel `CustomerOrders`.

Untuk step-by-step instruksi untuk menguji sampel berikut, lihat[Contoh kode Java](CodeSamples.Java.md).

**Example**  

```
package com.example.dynamodb;

import software.amazon.awssdk.core.waiters.WaiterResponse;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;
import software.amazon.awssdk.services.dynamodb.waiters.DynamoDbWaiter;

import java.util.HashMap;
import java.util.Map;

public class DocumentAPILocalSecondaryIndexExample {

    static DynamoDbClient client = DynamoDbClient.create();
    public static String tableName = "CustomerOrders";

    public static void main(String[] args) {
        createTable();
        loadData();
        query(null);
        query("IsOpenIndex");
        query("OrderCreationDateIndex");
        deleteTable(tableName);
    }

    public static void createTable() {
        CreateTableRequest request = CreateTableRequest.builder()
            .tableName(tableName)
            .provisionedThroughput(ProvisionedThroughput.builder()
                .readCapacityUnits(1L)
                .writeCapacityUnits(1L)
                .build())
            .attributeDefinitions(
                AttributeDefinition.builder().attributeName("CustomerId").attributeType(ScalarAttributeType.S).build(),
                AttributeDefinition.builder().attributeName("OrderId").attributeType(ScalarAttributeType.N).build(),
                AttributeDefinition.builder().attributeName("OrderCreationDate").attributeType(ScalarAttributeType.N).build(),
                AttributeDefinition.builder().attributeName("IsOpen").attributeType(ScalarAttributeType.N).build())
            .keySchema(
                KeySchemaElement.builder().attributeName("CustomerId").keyType(KeyType.HASH).build(),
                KeySchemaElement.builder().attributeName("OrderId").keyType(KeyType.RANGE).build())
            .localSecondaryIndexes(
                LocalSecondaryIndex.builder()
                    .indexName("OrderCreationDateIndex")
                    .keySchema(
                        KeySchemaElement.builder().attributeName("CustomerId").keyType(KeyType.HASH).build(),
                        KeySchemaElement.builder().attributeName("OrderCreationDate").keyType(KeyType.RANGE).build())
                    .projection(Projection.builder()
                        .projectionType(ProjectionType.INCLUDE)
                        .nonKeyAttributes("ProductCategory", "ProductName")
                        .build())
                    .build(),
                LocalSecondaryIndex.builder()
                    .indexName("IsOpenIndex")
                    .keySchema(
                        KeySchemaElement.builder().attributeName("CustomerId").keyType(KeyType.HASH).build(),
                        KeySchemaElement.builder().attributeName("IsOpen").keyType(KeyType.RANGE).build())
                    .projection(Projection.builder()
                        .projectionType(ProjectionType.ALL)
                        .build())
                    .build())
            .build();

        System.out.println("Creating table " + tableName + "...");
        client.createTable(request);

        try (DynamoDbWaiter waiter = client.waiter()) {
            WaiterResponse<DescribeTableResponse> response = waiter.waitUntilTableExists(r -> r.tableName(tableName));
            response.matched().response().ifPresent(System.out::println);
        }
    }

    public static void query(String indexName) {
        System.out.println("\n***********************************************************\n");
        System.out.println("Querying table " + tableName + "...");

        if ("IsOpenIndex".equals(indexName)) {
            System.out.println("\nUsing index: '" + indexName + "': Bob's orders that are open.");
            System.out.println("Only a user-specified list of attributes are returned\n");

            Map<String, AttributeValue> values = new HashMap<>();
            values.put(":v_custid", AttributeValue.builder().s("bob@example.com").build());
            values.put(":v_isopen", AttributeValue.builder().n("1").build());

            QueryRequest request = QueryRequest.builder()
                .tableName(tableName)
                .indexName(indexName)
                .keyConditionExpression("CustomerId = :v_custid and IsOpen = :v_isopen")
                .expressionAttributeValues(values)
                .projectionExpression("OrderCreationDate, ProductCategory, ProductName, OrderStatus")
                .build();

            System.out.println("Query: printing results...");
            client.query(request).items().forEach(System.out::println);

        } else if ("OrderCreationDateIndex".equals(indexName)) {
            System.out.println("\nUsing index: '" + indexName + "': Bob's orders that were placed after 01/31/2015.");
            System.out.println("Only the projected attributes are returned\n");

            Map<String, AttributeValue> values = new HashMap<>();
            values.put(":v_custid", AttributeValue.builder().s("bob@example.com").build());
            values.put(":v_orddate", AttributeValue.builder().n("20150131").build());

            QueryRequest request = QueryRequest.builder()
                .tableName(tableName)
                .indexName(indexName)
                .keyConditionExpression("CustomerId = :v_custid and OrderCreationDate >= :v_orddate")
                .expressionAttributeValues(values)
                .select(Select.ALL_PROJECTED_ATTRIBUTES)
                .build();

            System.out.println("Query: printing results...");
            client.query(request).items().forEach(System.out::println);

        } else {
            System.out.println("\nNo index: All of Bob's orders, by OrderId:\n");

            Map<String, AttributeValue> values = new HashMap<>();
            values.put(":v_custid", AttributeValue.builder().s("bob@example.com").build());

            QueryRequest request = QueryRequest.builder()
                .tableName(tableName)
                .keyConditionExpression("CustomerId = :v_custid")
                .expressionAttributeValues(values)
                .build();

            System.out.println("Query: printing results...");
            client.query(request).items().forEach(System.out::println);
        }
    }

    public static void deleteTable(String tableName) {
        System.out.println("Deleting table " + tableName + "...");
        client.deleteTable(DeleteTableRequest.builder().tableName(tableName).build());

        try (DynamoDbWaiter waiter = client.waiter()) {
            waiter.waitUntilTableNotExists(r -> r.tableName(tableName));
        }
    }

    public static void loadData() {
        System.out.println("Loading data into table " + tableName + "...");

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("alice@example.com").build(),
            "OrderId", AttributeValue.builder().n("1").build(),
            "IsOpen", AttributeValue.builder().n("1").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150101").build(),
            "ProductCategory", AttributeValue.builder().s("Book").build(),
            "ProductName", AttributeValue.builder().s("The Great Outdoors").build(),
            "OrderStatus", AttributeValue.builder().s("PACKING ITEMS").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("alice@example.com").build(),
            "OrderId", AttributeValue.builder().n("2").build(),
            "IsOpen", AttributeValue.builder().n("1").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150221").build(),
            "ProductCategory", AttributeValue.builder().s("Bike").build(),
            "ProductName", AttributeValue.builder().s("Super Mountain").build(),
            "OrderStatus", AttributeValue.builder().s("ORDER RECEIVED").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("alice@example.com").build(),
            "OrderId", AttributeValue.builder().n("3").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150304").build(),
            "ProductCategory", AttributeValue.builder().s("Music").build(),
            "ProductName", AttributeValue.builder().s("A Quiet Interlude").build(),
            "OrderStatus", AttributeValue.builder().s("IN TRANSIT").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("176493").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("1").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150111").build(),
            "ProductCategory", AttributeValue.builder().s("Movie").build(),
            "ProductName", AttributeValue.builder().s("Calm Before The Storm").build(),
            "OrderStatus", AttributeValue.builder().s("SHIPPING DELAY").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("859323").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("2").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150124").build(),
            "ProductCategory", AttributeValue.builder().s("Music").build(),
            "ProductName", AttributeValue.builder().s("E-Z Listening").build(),
            "OrderStatus", AttributeValue.builder().s("DELIVERED").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("756943").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("3").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150221").build(),
            "ProductCategory", AttributeValue.builder().s("Music").build(),
            "ProductName", AttributeValue.builder().s("Symphony 9").build(),
            "OrderStatus", AttributeValue.builder().s("DELIVERED").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("645193").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("4").build(),
            "IsOpen", AttributeValue.builder().n("1").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150222").build(),
            "ProductCategory", AttributeValue.builder().s("Hardware").build(),
            "ProductName", AttributeValue.builder().s("Extra Heavy Hammer").build(),
            "OrderStatus", AttributeValue.builder().s("PACKING ITEMS").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("5").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150309").build(),
            "ProductCategory", AttributeValue.builder().s("Book").build(),
            "ProductName", AttributeValue.builder().s("How To Cook").build(),
            "OrderStatus", AttributeValue.builder().s("IN TRANSIT").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("440185").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("6").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150318").build(),
            "ProductCategory", AttributeValue.builder().s("Luggage").build(),
            "ProductName", AttributeValue.builder().s("Really Big Suitcase").build(),
            "OrderStatus", AttributeValue.builder().s("DELIVERED").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("893927").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("7").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150324").build(),
            "ProductCategory", AttributeValue.builder().s("Golf").build(),
            "ProductName", AttributeValue.builder().s("PGA Pro II").build(),
            "OrderStatus", AttributeValue.builder().s("OUT FOR DELIVERY").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("383283").build()));
    }

    private static void putItem(Map<String, AttributeValue> item) {
        client.putItem(PutItemRequest.builder().tableName(tableName).item(item).build());
    }
}
```

# Menggunakan Indeks Sekunder Lokal: .NET
<a name="LSILowLevelDotNet"></a>

**Topics**
+ [Membuat tabel dengan Indeks Sekunder Lokal](#LSILowLevelDotNet.CreateTableWithIndex)
+ [Mendeskripsikan tabel dengan Indeks Sekunder Lokal](#LSILowLevelDotNet.DescribeTableWithIndex)
+ [Mengkueri Indeks Sekunder Lokal](#LSILowLevelDotNet.QueryAnIndex)
+ [Contoh: Indeks Sekunder Lokal menggunakan API tingkat AWS SDK untuk .NET rendah](LSILowLevelDotNet.Example.md)

Anda dapat menggunakan API AWS SDK untuk .NET tingkat rendah untuk membuat tabel Amazon DynamoDB dengan satu atau beberapa indeks sekunder lokal, menjelaskan indeks pada tabel, dan melakukan kueri menggunakan indeks. Operasi ini dipetakan ke tindakan DynamoDB API tingkat rendah yang sesuai. Untuk informasi selengkapnya, lihat [Contoh kode .NET](CodeSamples.DotNet.md). 

Berikut ini adalah langkah-langkah umum untuk operasi tabel menggunakan API tingkat rendah .NET. 

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Berikan parameter wajib dan opsional untuk operasi dengan membuat objek permintaan yang sesuai.

   Misalnya, buat objek `CreateTableRequest` untuk membuat tabel dan objek `QueryRequest` untuk mengkueri tabel atau indeks. 

1. Jalankan metode sesuai yang ditentukan oleh klien yang Anda buat pada langkah sebelumnya. 

## Membuat tabel dengan Indeks Sekunder Lokal
<a name="LSILowLevelDotNet.CreateTableWithIndex"></a>

Indeks sekunder lokal harus dibuat pada saat Anda membuat tabel. Untuk melakukannya, gunakan `CreateTable` dan berikan spesifikasi Anda untuk satu atau beberapa indeks sekunder lokal. Contoh kode C\$1 berikut membuat tabel untuk menyimpan informasi tentang lagu dalam koleksi musik. Kunci partisinya adalah `Artist` dan kunci urutannya adalah `SongTitle`. Indeks sekunder, `AlbumTitleIndex`, memfasilitasi kueri berdasarkan judul album. 

Berikut ini adalah langkah-langkah untuk membuat tabel dengan indeks sekunder lokal, menggunakan API tingkat rendah .NET. 

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Buat instans dari kelas `CreateTableRequest` untuk memberikan informasi permintaan. 

   Anda harus memberikan nama tabel, kunci primernya, dan nilai throughput yang ditentukan. Untuk indeks sekunder lokal, Anda harus memberikan nama indeks, nama dan jenis data kunci urutan indeks, skema kunci untuk indeks, dan proyeksi atribut.

1. Jalankan metode `CreateTable` dengan menentukan objek permintaan sebagai parameter.

Contoh kode \$1C berikut mendemonstrasikan langkah sebelumnya. Kode ini membuat tabel (`Music`) dengan indeks sekunder pada atribut `AlbumTitle`. Kunci urutan dan kunci partisi tabel, ditambah kunci urutan indeks, adalah satu-satunya atribut yang diproyeksikan ke dalam indeks.

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "Music";

CreateTableRequest createTableRequest = new CreateTableRequest()
{
    TableName = tableName
};

//ProvisionedThroughput
createTableRequest.ProvisionedThroughput = new ProvisionedThroughput()
{
    ReadCapacityUnits = (long)5,
    WriteCapacityUnits = (long)5
};

//AttributeDefinitions
List<AttributeDefinition> attributeDefinitions = new List<AttributeDefinition>();

attributeDefinitions.Add(new AttributeDefinition()
{
    AttributeName = "Artist",
    AttributeType = "S"
});

attributeDefinitions.Add(new AttributeDefinition()
 {
     AttributeName = "SongTitle",
     AttributeType = "S"
 });

attributeDefinitions.Add(new AttributeDefinition()
 {
     AttributeName = "AlbumTitle",
     AttributeType = "S"
 });

createTableRequest.AttributeDefinitions = attributeDefinitions;

//KeySchema
List<KeySchemaElement> tableKeySchema = new List<KeySchemaElement>();

tableKeySchema.Add(new KeySchemaElement() { AttributeName = "Artist", KeyType = "HASH" });  //Partition key
tableKeySchema.Add(new KeySchemaElement() { AttributeName = "SongTitle", KeyType = "RANGE" });  //Sort key

createTableRequest.KeySchema = tableKeySchema;

List<KeySchemaElement> indexKeySchema = new List<KeySchemaElement>();
indexKeySchema.Add(new KeySchemaElement() { AttributeName = "Artist", KeyType = "HASH" });  //Partition key
indexKeySchema.Add(new KeySchemaElement() { AttributeName = "AlbumTitle", KeyType = "RANGE" });  //Sort key

Projection projection = new Projection() { ProjectionType = "INCLUDE" };

List<string> nonKeyAttributes = new List<string>();
nonKeyAttributes.Add("Genre");
nonKeyAttributes.Add("Year");
projection.NonKeyAttributes = nonKeyAttributes;

LocalSecondaryIndex localSecondaryIndex = new LocalSecondaryIndex()
{
    IndexName = "AlbumTitleIndex",
    KeySchema = indexKeySchema,
    Projection = projection
};

List<LocalSecondaryIndex> localSecondaryIndexes = new List<LocalSecondaryIndex>();
localSecondaryIndexes.Add(localSecondaryIndex);
createTableRequest.LocalSecondaryIndexes = localSecondaryIndexes;

CreateTableResponse result = client.CreateTable(createTableRequest);
Console.WriteLine(result.CreateTableResult.TableDescription.TableName);
Console.WriteLine(result.CreateTableResult.TableDescription.TableStatus);
```

Anda harus menunggu hingga DynamoDB membuat tabel dan menetapkan status tabel menjadi `ACTIVE`. Setelah itu, Anda bisa mulai memasukkan item data ke dalam tabel.

## Mendeskripsikan tabel dengan Indeks Sekunder Lokal
<a name="LSILowLevelDotNet.DescribeTableWithIndex"></a>

Untuk mendapatkan informasi tentang indeks sekunder lokal pada tabel, gunakan API `DescribeTable`. Untuk setiap indeks, Anda dapat mengakses namanya, skema kunci, dan atribut yang diproyeksikan.

Berikut ini adalah langkah-langkah untuk mengakses informasi indeks sekunder lokal suatu tabel menggunakan API tingkat rendah .NET. 

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Buat instans dari kelas `DescribeTableRequest` untuk memberikan informasi permintaan. Anda harus memberikan nama tabel.

1. Jalankan metode `describeTable` dengan menentukan objek permintaan sebagai parameter.

Contoh kode \$1C berikut mendemonstrasikan langkah sebelumnya.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "Music";

DescribeTableResponse response = client.DescribeTable(new DescribeTableRequest() { TableName = tableName });
List<LocalSecondaryIndexDescription> localSecondaryIndexes =
    response.DescribeTableResult.Table.LocalSecondaryIndexes;

// This code snippet will work for multiple indexes, even though
// there is only one index in this example.
foreach (LocalSecondaryIndexDescription lsiDescription in localSecondaryIndexes)
{
    Console.WriteLine("Info for index " + lsiDescription.IndexName + ":");

    foreach (KeySchemaElement kse in lsiDescription.KeySchema)
    {
        Console.WriteLine("\t" + kse.AttributeName + ": key type is " + kse.KeyType);
    }

    Projection projection = lsiDescription.Projection;

    Console.WriteLine("\tThe projection type is: " + projection.ProjectionType);

    if (projection.ProjectionType.ToString().Equals("INCLUDE"))
    {
        Console.WriteLine("\t\tThe non-key projected attributes are:");

        foreach (String s in projection.NonKeyAttributes)
        {
            Console.WriteLine("\t\t" + s);
        }

    }
}
```

## Mengkueri Indeks Sekunder Lokal
<a name="LSILowLevelDotNet.QueryAnIndex"></a>

Anda dapat menggunakan `Query` pada indeks sekunder lokal, sama seperti Anda `Query` tabel. Anda harus menentukan nama indeks, kriteria kueri untuk kunci urutan indeks, dan atribut yang ingin Anda kembalikan. Dalam contoh ini, indeks adalah `AlbumTitleIndex`, dan kunci urutan indeks adalah `AlbumTitle`. 

Satu-satunya atribut yang dikembalikan adalah atribut yang telah diproyeksikan ke dalam indeks. Anda dapat memodifikasi kueri ini untuk memilih atribut non-kunci juga, tetapi ini akan memerlukan aktivitas pengambilan tabel yang relatif mahal. Untuk informasi selengkapnya tentang pengambilan tabel, lihat [Proyeksi atribut](LSI.md#LSI.Projections)

Berikut ini adalah langkah-langkah untuk mengkueri indeks sekunder lokal menggunakan API tingkat rendah .NET. 

1. Buat instans dari kelas `AmazonDynamoDBClient`.

1. Buat instans dari kelas `QueryRequest` untuk memberikan informasi permintaan.

1. Jalankan metode `query` dengan menentukan objek permintaan sebagai parameter.

Contoh kode \$1C berikut mendemonstrasikan langkah sebelumnya.

**Example**  

```
QueryRequest queryRequest = new QueryRequest
{
    TableName = "Music",
    IndexName = "AlbumTitleIndex",
    Select = "ALL_ATTRIBUTES",
    ScanIndexForward = true,
    KeyConditionExpression = "Artist = :v_artist and AlbumTitle = :v_title",
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":v_artist",new AttributeValue {S = "Acme Band"}},
        {":v_title",new AttributeValue {S = "Songs About Life"}}
    },
};

QueryResponse response = client.Query(queryRequest);

foreach (var attribs in response.Items)
{
    foreach (var attrib in attribs)
    {
        Console.WriteLine(attrib.Key + " ---> " + attrib.Value.S);
    }
    Console.WriteLine();
}
```

# Contoh: Indeks Sekunder Lokal menggunakan API tingkat AWS SDK untuk .NET rendah
<a name="LSILowLevelDotNet.Example"></a>

Contoh kode C\$1 berikut menunjukkan cara menggunakan indeks sekunder lokal di Amazon DynamoDB. Contoh membuat tabel bernama `CustomerOrders` dengan kunci partisi `CustomerId` dan kunci urutan `OrderId`. Ada dua indeks sekunder lokal di tabel ini:
+ `OrderCreationDateIndex` — Kunci urutannya adalah `OrderCreationDate`, dan atribut berikut diproyeksikan ke dalam indeks:
  + `ProductCategory`
  + `ProductName`
  + `OrderStatus`
  + `ShipmentTrackingId`
+ `IsOpenIndex` — Kunci urutannya adalah `IsOpen`, dan semua atribut tabel diproyeksikan ke dalam indeks.

Setelah tabel `CustomerOrders` dibuat, program memuat tabel dengan data yang mewakili pesanan pelanggan. Kemudian mengkueri data menggunakan indeks sekunder lokal. Terakhir, program menghapus tabel `CustomerOrders`.

Untuk step-by-step instruksi untuk menguji contoh berikut, lihat[Contoh kode .NET](CodeSamples.DotNet.md).

**Example**  

```
using System;
using System.Collections.Generic;
using System.Linq;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;
using Amazon.SecurityToken;

namespace com.amazonaws.codesamples
{
    class LowLevelLocalSecondaryIndexExample
    {
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();
        private static string tableName = "CustomerOrders";

        static void Main(string[] args)
        {
            try
            {
                CreateTable();
                LoadData();

                Query(null);
                Query("IsOpenIndex");
                Query("OrderCreationDateIndex");

                DeleteTable(tableName);

                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (AmazonDynamoDBException e) { Console.WriteLine(e.Message); }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }
        }

        private static void CreateTable()
        {
            var createTableRequest =
                new CreateTableRequest()
                {
                    TableName = tableName,
                    ProvisionedThroughput =
                    new ProvisionedThroughput()
                    {
                        ReadCapacityUnits = (long)1,
                        WriteCapacityUnits = (long)1
                    }
                };

            var attributeDefinitions = new List<AttributeDefinition>()
        {
            // Attribute definitions for table primary key
            { new AttributeDefinition() {
                  AttributeName = "CustomerId", AttributeType = "S"
              } },
            { new AttributeDefinition() {
                  AttributeName = "OrderId", AttributeType = "N"
              } },
            // Attribute definitions for index primary key
            { new AttributeDefinition() {
                  AttributeName = "OrderCreationDate", AttributeType = "N"
              } },
            { new AttributeDefinition() {
                  AttributeName = "IsOpen", AttributeType = "N"
              }}
        };

            createTableRequest.AttributeDefinitions = attributeDefinitions;

            // Key schema for table
            var tableKeySchema = new List<KeySchemaElement>()
        {
            { new KeySchemaElement() {
                  AttributeName = "CustomerId", KeyType = "HASH"
              } },                                                  //Partition key
            { new KeySchemaElement() {
                  AttributeName = "OrderId", KeyType = "RANGE"
              } }                                                //Sort key
        };

            createTableRequest.KeySchema = tableKeySchema;

            var localSecondaryIndexes = new List<LocalSecondaryIndex>();

            // OrderCreationDateIndex
            LocalSecondaryIndex orderCreationDateIndex = new LocalSecondaryIndex()
            {
                IndexName = "OrderCreationDateIndex"
            };

            // Key schema for OrderCreationDateIndex
            var indexKeySchema = new List<KeySchemaElement>()
        {
            { new KeySchemaElement() {
                  AttributeName = "CustomerId", KeyType = "HASH"
              } },                                                    //Partition key
            { new KeySchemaElement() {
                  AttributeName = "OrderCreationDate", KeyType = "RANGE"
              } }                                                            //Sort key
        };

            orderCreationDateIndex.KeySchema = indexKeySchema;

            // Projection (with list of projected attributes) for
            // OrderCreationDateIndex
            var projection = new Projection()
            {
                ProjectionType = "INCLUDE"
            };

            var nonKeyAttributes = new List<string>()
        {
            "ProductCategory",
            "ProductName"
        };
            projection.NonKeyAttributes = nonKeyAttributes;

            orderCreationDateIndex.Projection = projection;

            localSecondaryIndexes.Add(orderCreationDateIndex);

            // IsOpenIndex
            LocalSecondaryIndex isOpenIndex
                = new LocalSecondaryIndex()
                {
                    IndexName = "IsOpenIndex"
                };

            // Key schema for IsOpenIndex
            indexKeySchema = new List<KeySchemaElement>()
        {
            { new KeySchemaElement() {
                  AttributeName = "CustomerId", KeyType = "HASH"
              }},                                                     //Partition key
            { new KeySchemaElement() {
                  AttributeName = "IsOpen", KeyType = "RANGE"
              }}                                                  //Sort key
        };

            // Projection (all attributes) for IsOpenIndex
            projection = new Projection()
            {
                ProjectionType = "ALL"
            };

            isOpenIndex.KeySchema = indexKeySchema;
            isOpenIndex.Projection = projection;

            localSecondaryIndexes.Add(isOpenIndex);

            // Add index definitions to CreateTable request
            createTableRequest.LocalSecondaryIndexes = localSecondaryIndexes;

            Console.WriteLine("Creating table " + tableName + "...");
            client.CreateTable(createTableRequest);
            WaitUntilTableReady(tableName);
        }

        public static void Query(string indexName)
        {
            Console.WriteLine("\n***********************************************************\n");
            Console.WriteLine("Querying table " + tableName + "...");

            QueryRequest queryRequest = new QueryRequest()
            {
                TableName = tableName,
                ConsistentRead = true,
                ScanIndexForward = true,
                ReturnConsumedCapacity = "TOTAL"
            };


            String keyConditionExpression = "CustomerId = :v_customerId";
            Dictionary<string, AttributeValue> expressionAttributeValues = new Dictionary<string, AttributeValue> {
            {":v_customerId", new AttributeValue {
                 S = "bob@example.com"
             }}
        };


            if (indexName == "IsOpenIndex")
            {
                Console.WriteLine("\nUsing index: '" + indexName
                          + "': Bob's orders that are open.");
                Console.WriteLine("Only a user-specified list of attributes are returned\n");
                queryRequest.IndexName = indexName;

                keyConditionExpression += " and IsOpen = :v_isOpen";
                expressionAttributeValues.Add(":v_isOpen", new AttributeValue
                {
                    N = "1"
                });

                // ProjectionExpression
                queryRequest.ProjectionExpression = "OrderCreationDate, ProductCategory, ProductName, OrderStatus";
            }
            else if (indexName == "OrderCreationDateIndex")
            {
                Console.WriteLine("\nUsing index: '" + indexName
                          + "': Bob's orders that were placed after 01/31/2013.");
                Console.WriteLine("Only the projected attributes are returned\n");
                queryRequest.IndexName = indexName;

                keyConditionExpression += " and OrderCreationDate > :v_Date";
                expressionAttributeValues.Add(":v_Date", new AttributeValue
                {
                    N = "20130131"
                });

                // Select
                queryRequest.Select = "ALL_PROJECTED_ATTRIBUTES";
            }
            else
            {
                Console.WriteLine("\nNo index: All of Bob's orders, by OrderId:\n");
            }
            queryRequest.KeyConditionExpression = keyConditionExpression;
            queryRequest.ExpressionAttributeValues = expressionAttributeValues;

            var result = client.Query(queryRequest);
            var items = result.Items;
            foreach (var currentItem in items)
            {
                foreach (string attr in currentItem.Keys)
                {
                    if (attr == "OrderId" || attr == "IsOpen"
                        || attr == "OrderCreationDate")
                    {
                        Console.WriteLine(attr + "---> " + currentItem[attr].N);
                    }
                    else
                    {
                        Console.WriteLine(attr + "---> " + currentItem[attr].S);
                    }
                }
                Console.WriteLine();
            }
            Console.WriteLine("\nConsumed capacity: " + result.ConsumedCapacity.CapacityUnits + "\n");
        }

        private static void DeleteTable(string tableName)
        {
            Console.WriteLine("Deleting table " + tableName + "...");
            client.DeleteTable(new DeleteTableRequest()
            {
                TableName = tableName
            });
            WaitForTableToBeDeleted(tableName);
        }

        public static void LoadData()
        {
            Console.WriteLine("Loading data into table " + tableName + "...");

            Dictionary<string, AttributeValue> item = new Dictionary<string, AttributeValue>();

            item["CustomerId"] = new AttributeValue
            {
                S = "alice@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "1"
            };
            item["IsOpen"] = new AttributeValue
            {
                N = "1"
            };
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130101"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Book"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "The Great Outdoors"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "PACKING ITEMS"
            };
            /* no ShipmentTrackingId attribute */
            PutItemRequest putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "alice@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "2"
            };
            item["IsOpen"] = new AttributeValue
            {
                N = "1"
            };
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130221"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Bike"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Super Mountain"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "ORDER RECEIVED"
            };
            /* no ShipmentTrackingId attribute */
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "alice@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "3"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130304"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Music"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "A Quiet Interlude"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "IN TRANSIT"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "176493"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "1"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130111"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Movie"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Calm Before The Storm"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "SHIPPING DELAY"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "859323"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "2"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130124"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Music"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "E-Z Listening"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "DELIVERED"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "756943"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "3"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130221"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Music"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Symphony 9"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "DELIVERED"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "645193"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "4"
            };
            item["IsOpen"] = new AttributeValue
            {
                N = "1"
            };
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130222"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Hardware"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Extra Heavy Hammer"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "PACKING ITEMS"
            };
            /* no ShipmentTrackingId attribute */
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "5"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130309"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Book"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "How To Cook"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "IN TRANSIT"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "440185"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "6"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130318"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Luggage"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Really Big Suitcase"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "DELIVERED"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "893927"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "7"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130324"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Golf"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "PGA Pro II"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "OUT FOR DELIVERY"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "383283"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);
        }

        private static void WaitUntilTableReady(string tableName)
        {
            string status = null;
            // Let us wait until table is created. Call DescribeTable.
            do
            {
                System.Threading.Thread.Sleep(5000); // Wait 5 seconds.
                try
                {
                    var res = client.DescribeTable(new DescribeTableRequest
                    {
                        TableName = tableName
                    });

                    Console.WriteLine("Table name: {0}, status: {1}",
                              res.Table.TableName,
                              res.Table.TableStatus);
                    status = res.Table.TableStatus;
                }
                catch (ResourceNotFoundException)
                {
                    // DescribeTable is eventually consistent. So you might
                    // get resource not found. So we handle the potential exception.
                }
            } while (status != "ACTIVE");
        }

        private static void WaitForTableToBeDeleted(string tableName)
        {
            bool tablePresent = true;

            while (tablePresent)
            {
                System.Threading.Thread.Sleep(5000); // Wait 5 seconds.
                try
                {
                    var res = client.DescribeTable(new DescribeTableRequest
                    {
                        TableName = tableName
                    });

                    Console.WriteLine("Table name: {0}, status: {1}",
                              res.Table.TableName,
                              res.Table.TableStatus);
                }
                catch (ResourceNotFoundException)
                {
                    tablePresent = false;
                }
            }
        }
    }
}
```

# Bekerja dengan Indeks Sekunder Lokal di DynamoDB AWS CLI
<a name="LCICli"></a>

Anda dapat menggunakan AWS CLI untuk membuat tabel Amazon DynamoDB dengan satu atau beberapa Indeks Sekunder Lokal, menjelaskan indeks pada tabel, dan melakukan kueri menggunakan indeks.

**Topics**
+ [Membuat tabel dengan Indeks Sekunder Lokal](#LCICli.CreateTableWithIndex)
+ [Mendeskripsikan tabel dengan Indeks Sekunder Lokal](#LCICli.DescribeTableWithIndex)
+ [Mengkueri Indeks Sekunder Lokal](#LCICli.QueryAnIndex)

## Membuat tabel dengan Indeks Sekunder Lokal
<a name="LCICli.CreateTableWithIndex"></a>

Indeks Sekunder Lokal harus dibuat pada saat Anda membuat tabel. Untuk melakukannya, gunakan parameter `create-table` dan berikan spesifikasi Anda untuk satu atau beberapa Indeks Sekunder Lokal. Contoh berikut membuat tabel (`Music`) untuk menyimpan informasi tentang lagu dalam koleksi musik. Kunci partisinya adalah `Artist` dan kunci urutannya adalah `SongTitle`. Indeks sekunder, `AlbumTitleIndex` pada atribut `AlbumTitle` memfasilitasi kueri berdasarkan judul album. 

```
aws dynamodb create-table \
    --table-name Music \
    --attribute-definitions AttributeName=Artist,AttributeType=S AttributeName=SongTitle,AttributeType=S \
        AttributeName=AlbumTitle,AttributeType=S  \
    --key-schema AttributeName=Artist,KeyType=HASH AttributeName=SongTitle,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5 \
    --local-secondary-indexes \
        "[{\"IndexName\": \"AlbumTitleIndex\",
        \"KeySchema\":[{\"AttributeName\":\"Artist\",\"KeyType\":\"HASH\"},
                      {\"AttributeName\":\"AlbumTitle\",\"KeyType\":\"RANGE\"}],
        \"Projection\":{\"ProjectionType\":\"INCLUDE\",  \"NonKeyAttributes\":[\"Genre\", \"Year\"]}}]"
```

Anda harus menunggu hingga DynamoDB membuat tabel dan menetapkan status tabel menjadi `ACTIVE`. Setelah itu, Anda bisa mulai memasukkan item data ke dalam tabel. Anda dapat menggunakan [describe-table](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/describe-table.html) untuk menentukan status pembuatan tabel. 

## Mendeskripsikan tabel dengan Indeks Sekunder Lokal
<a name="LCICli.DescribeTableWithIndex"></a>

Untuk mendapatkan informasi tentang indeks sekunder lokal pada tabel, gunakan parameter `describe-table`. Untuk setiap indeks, Anda dapat mengakses namanya, skema kunci, dan atribut yang diproyeksikan.

```
aws dynamodb describe-table --table-name Music
```

## Mengkueri Indeks Sekunder Lokal
<a name="LCICli.QueryAnIndex"></a>

Anda dapat menggunakan operasi `query` pada Indeks Sekunder Lokal dengan cara yang hampir sama seperti Anda `query` tabel. Anda harus menentukan nama indeks, kriteria kueri untuk kunci urutan indeks, dan atribut yang ingin Anda kembalikan. Dalam contoh ini, indeks adalah `AlbumTitleIndex` dan kunci urutan indeks adalah `AlbumTitle`. 

Satu-satunya atribut yang dikembalikan adalah atribut yang telah diproyeksikan ke dalam indeks. Anda dapat memodifikasi kueri ini untuk memilih atribut non-kunci juga, tetapi ini akan memerlukan aktivitas pengambilan tabel yang relatif mahal. Untuk informasi selengkapnya tentang pengambilan tabel, lihat [Proyeksi atribut](LSI.md#LSI.Projections).

```
aws dynamodb query \
    --table-name Music \
    --index-name AlbumTitleIndex \
    --key-condition-expression "Artist = :v_artist and AlbumTitle = :v_title" \
    --expression-attribute-values  '{":v_artist":{"S":"Acme Band"},":v_title":{"S":"Songs About Life"} }'
```

# Mengelola alur kerja kompleks dengan DynamoDB Transactions
<a name="transactions"></a>

Transaksi Amazon DynamoDB menyederhanakan pengalaman pengembang dalam membuat terkoordinasi all-or-nothing, perubahan ke beberapa item baik di dalam maupun di seluruh tabel. Transaksi memberikan atomisitas, konsistensi, isolasi, dan daya tahan (ACID) di DynamoDB, yang memungkinkan Anda menjaga kebenaran data dalam aplikasi Anda dengan lebih mudah.

Anda dapat menggunakan DynamoDB transaksional read and APIs write untuk mengelola alur kerja bisnis kompleks yang memerlukan penambahan, pembaruan, atau penghapusan beberapa item sebagai operasi tunggal. all-or-nothing Misalnya, developer video game dapat memastikan bahwa profil pemain diperbarui dengan benar saat mereka bertukar item dalam game atau melakukan pembelian dalam game.

Dengan transaksi API tulis, Anda dapat mengelompokkan beberapa tindakan `Put`, `Update`, `Delete`, dan `ConditionCheck`. Anda kemudian dapat mengirimkan tindakan sebagai operasi `TransactWriteItems` tunggal yang baik berhasil atau gagal sebagai unit. Hal yang sama berlaku untuk beberapa tindakan `Get`, yang dapat Anda kelompokkan dan kirimkan sebagai operasi `TransactGetItems` tunggal.

Tidak ada biaya tambahan untuk mengaktifkan transaksi untuk tabel DynamoDB Anda. Anda hanya membayar untuk baca atau tulis yang merupakan bagian dari transaksi Anda. DynamoDB melakukan dua baca atau tulis mendasar dari setiap item dalam transaksi: satu untuk mempersiapkan transaksi dan satu untuk melakukan transaksi. Kedua read/write operasi yang mendasari ini terlihat di CloudWatch metrik Amazon Anda.

Untuk memulai transaksi DynamoDB, unduh SDK AWS terbaru atau (). AWS Command Line Interface AWS CLI Kemudian ikuti [Contoh DynamoDB transactions](transaction-example.md).

Bagian berikut memberikan gambaran rinci tentang transaksi APIs dan bagaimana Anda dapat menggunakannya di DynamoDB.

**Topics**
+ [Cara kerjanya](transaction-apis.md)
+ [Menggunakan IAM dengan transactions](transaction-apis-iam.md)
+ [Contoh kode](transaction-example.md)

# Amazon DynamoDB Transactions: Cara kerjanya
<a name="transaction-apis"></a>

Dengan transaksi Amazon DynamoDB, Anda dapat mengelompokkan beberapa tindakan bersama-sama dan mengirimkannya sebagai satu atau all-or-nothing `TransactWriteItems` operasi. `TransactGetItems` Bagian berikut menjelaskan operasi API, manajemen kapasitas, praktik terbaik, dan detail lainnya tentang menggunakan operasi transaksional di DynamoDB.

**Topics**
+ [TransactWriteItems API](#transaction-apis-txwriteitems)
+ [TransactGetItems API](#transaction-apis-txgetitems)
+ [Tingkat isolasi untuk DynamoDB transactions](#transaction-isolation)
+ [Penanganan konflik transaksi di DynamoDB](#transaction-conflict-handling)
+ [Menggunakan transaksional di APIs DynamoDB Accelerator (DAX)](#transaction-apis-dax)
+ [Manajemen kapasitas untuk transaksi](#transaction-capacity-handling)
+ [Praktik terbaik untuk transactions](#transaction-best-practices)
+ [Menggunakan transaksional APIs dengan tabel global](#transaction-integration)
+ [Transaksi DynamoDB AWSLabs vs. perpustakaan klien transaksi](#transaction-vs-library)

## TransactWriteItems API
<a name="transaction-apis-txwriteitems"></a>

`TransactWriteItems`adalah operasi penulisan sinkron dan idempoten yang mengelompokkan hingga 100 tindakan penulisan dalam satu operasi. all-or-nothing Tindakan ini dapat menargetkan hingga 100 item berbeda dalam satu atau lebih tabel DynamoDB dalam akun AWS yang sama dan di Wilayah yang sama. Ukuran agregat item dalam transaksi tidak dapat melebihi 4 MB. Tindakan tersebut diselesaikan secara atomik, sehingga semuanya berhasil atau tidak satu pun yang berhasil.

**catatan**  
 Operasi `TransactWriteItems` berbeda dari operasi `BatchWriteItem` dalam hal semua tindakan yang di dalamnya harus berhasil diselesaikan, atau tidak ada perubahan yang dibuat sama sekali. Dengan operasi `BatchWriteItem`, mungkin bahwa hanya beberapa tindakan dalam batch yang berhasil sementara yang lain tidak. 
 Transaksi tidak dapat dilakukan dengan menggunakan indeks. 

Anda tidak dapat menargetkan item yang sama dengan beberapa operasi dalam transaksi yang sama. Misalnya, Anda tidak dapat melakukan `ConditionCheck` dan juga tindakan `Update` pada item yang sama dalam transaksi yang sama.

Anda dapat menambahkan jenis tindakan berikut pada transaksi:
+ `Put` — Memulai operasi `PutItem` untuk membuat item baru atau mengganti item lama dengan item baru, kondisional atau tanpa menentukan syarat apa pun.
+ `Update` — Memulai operasi `UpdateItem` untuk mengedit atribut item yang ada atau menambahkan item baru ke tabel jika belum ada. Gunakan tindakan ini untuk menambah, menghapus, atau memperbarui atribut pada item yang ada secara dengan syarat maupun tanpa syarat.
+ `Delete` — Memulai operasi `DeleteItem` untuk menghapus satu item dalam tabel yang diidentifikasi oleh kunci primernya.
+ `ConditionCheck` — Memeriksa bahwa item ada atau periksa kondisi atribut tertentu dari item.

Ketika transaksi selesai di DynamoDB, perubahannya mulai menyebar ke indeks sekunder global GSIs (), aliran, dan cadangan. Propagasi ini terjadi secara bertahap: catatan aliran dari transaksi yang sama mungkin muncul pada waktu yang berbeda dan dapat disisipkan dengan catatan dari transaksi lain. Konsumen streaming tidak boleh menganggap atomisitas transaksi atau jaminan pemesanan.

Untuk memastikan snapshot atom dari item yang dimodifikasi dalam transaksi, gunakan TransactGetItems operasi untuk membaca semua item yang relevan bersama-sama. Operasi ini memberikan tampilan data yang konsisten, memastikan Anda melihat semua perubahan dari transaksi yang diselesaikan atau tidak sama sekali.

Karena propagasi tidak langsung, jika tabel dipulihkan dari backup ([RestoreTableFromBackup](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_RestoreTableFromBackup.html)) atau diekspor ke titik waktu ([ExportTableToPointInTime](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ExportTableToPointInTime.html)) pertengahan propagasi, itu hanya dapat berisi beberapa perubahan yang dibuat selama transaksi baru-baru ini.

### Idempotensi
<a name="transaction-apis-txwriteitems-idempotency"></a>

Anda dapat menyertakan token klien ketika Anda membuat panggilan `TransactWriteItems` untuk memastikan bahwa permintaan tersebut *idempoten*. Menjadikan transaksi Anda idempoten membantu mencegah kesalahan aplikasi jika operasi yang sama diajukan beberapa kali karena waktu habis koneksi atau masalah konektivitas lainnya.

Jika panggilan `TransactWriteItems` asli berhasil, panggilan `TransactWriteItems` berikutnya dengan token klien yang sama berhasil kembali tanpa membuat perubahan apa pun. Jika parameter `ReturnConsumedCapacity` diatur, panggilan `TransactWriteItems` awal mengembalikan jumlah unit kapasitas tulis yang dikonsumsi dalam membuat perubahan. Panggilan `TransactWriteItems` selanjutnya dengan token klien yang sama mengembalikan jumlah unit kapasitas baca yang dikonsumsi dalam membaca item.

**Poin penting tentang idempotensi**
+ Token klien berlaku selama 10 menit setelah permintaan yang menggunakannya selesai. Setelah 10 menit, setiap permintaan yang menggunakan token klien yang sama diperlakukan sebagai permintaan baru. Anda tidak boleh menggunakan kembali token klien yang sama untuk permintaan yang sama setelah 10 menit.
+ Jika Anda mengulangi permintaan dengan token klien yang sama dalam jendela idempotensi 10 menit tetapi mengubah beberapa parameter permintaan lainnya, DynamoDB mengembalikan pengecualian `IdempotentParameterMismatch`.

### Penanganan kesalahan untuk penulisan
<a name="transaction-apis-txwriteitems-errors"></a>

Transaksi tulis tidak berhasil dalam situasi berikut:
+ Ketika syarat di salah satu ekspresisyarat tidak terpenuhi.
+ Ketika kesalahan validasi transaksi terjadi karena lebih dari satu tindakan dalam operasi `TransactWriteItems` yang sama menargetkan item yang sama.
+ Saat permintaan `TransactWriteItems` bertentangan dengan operasi `TransactWriteItems` yang sedang berlangsung pada satu atau lebih item dalam permintaan `TransactWriteItems`. Dalam kasus ini, permintaan gagal dengan `TransactionCanceledException`.
+ Ketika ada kapasitas yang ditetapkan tidak mencukupi untuk penyelesaian transaksi.
+ Ketika ukuran item menjadi terlalu besar (lebih besar dari 400 KB), atau indeks sekunder lokal (LSI) menjadi terlalu besar, atau kesalahan validasi serupa terjadi karena perubahan yang dilakukan oleh transaksi.
+ Ketika ada kesalahan pengguna, seperti format data yang tidak valid.

 Untuk informasi selengkapnya tentang bagaimana pertentangan dengan operasi `TransactWriteItems` ditangani, lihat [Penanganan konflik transaksi di DynamoDB](#transaction-conflict-handling).

## TransactGetItems API
<a name="transaction-apis-txgetitems"></a>

`TransactGetItems` adalah operasi baca sinkron yang mengelompokkan hingga 100 tindakan `Get` menjadi satu. Tindakan ini dapat menargetkan hingga 100 item berbeda dalam satu atau lebih tabel DynamoDB dalam akun dan Wilayah yang AWS sama. Ukuran agregat item dalam transaksi tidak dapat melebihi 4 MB. 

Tindakan `Get` dilakukan secara atom sehingga semuanya berhasil atau semuanya gagal:
+ `Get` — Memulai operasi `GetItem` untuk mengambil satu set atribut untuk item dengan kunci primer yang diberikan. Jika tidak ditemukan item yang cocok, `Get` tidak mengembalikan data apa pun.

### Penanganan kesalahan untuk pembacaan
<a name="transaction-apis-txgetitems-errors"></a>

Transaksi baca tidak berhasil dalam situasi berikut:
+ Saat permintaan `TransactGetItems` bertentangan dengan operasi `TransactWriteItems` yang sedang berlangsung pada satu atau lebih item dalam permintaan `TransactGetItems`. Dalam kasus ini, permintaan gagal dengan `TransactionCanceledException`.
+ Ketika ada kapasitas yang ditetapkan tidak mencukupi untuk penyelesaian transaksi.
+ Ketika ada kesalahan pengguna, seperti format data yang tidak valid.

 Untuk informasi selengkapnya tentang bagaimana pertentangan dengan operasi `TransactGetItems` ditangani, lihat [Penanganan konflik transaksi di DynamoDB](#transaction-conflict-handling).

## Tingkat isolasi untuk DynamoDB transactions
<a name="transaction-isolation"></a>

Tingkat isolasi operasi transaksional (`TransactWriteItems` atau `TransactGetItems`) dan operasi lainnya adalah sebagai berikut.

### DAPAT DISERIALKAN
<a name="transaction-isolation-serializable"></a>

Isolasi yang *dapat diserialkan* memastikan bahwa hasil dari beberapa operasi bersamaan sama seperti jika tidak ada operasi dimulai hingga operasi sebelumnya telah selesai.

Ada isolasi serialisasi antara jenis operasi berikut:
+ Antara operasi transaksional dan operasi tulis standar (`PutItem`, `UpdateItem`, atau `DeleteItem`).
+ Antara operasi transaksional dan operasi baca standar (`GetItem`).
+ Antara operasi `TransactWriteItems` dan operasi `TransactGetItems`.

Meskipun ada isolasi serialisasi antara operasi transaksional, dan setiap standar individu menulis dalam suatu `BatchWriteItem` operasi, tidak ada isolasi serial antara transaksi dan operasi sebagai satu unit. `BatchWriteItem`

Demikian pula, tingkat isolasi antara operasi transaksional dan individu `GetItems` dalam operasi `BatchGetItem` dapat diserialisasikan. Tetapi tahap isolasi antara transaksi dan operasi `BatchGetItem` sebagai unit adalah *read-committed*.

Permintaan `GetItem` tunggal dapat diserialisasikan sehubungan dengan permintaan `TransactWriteItems` dalam salah satu dari dua cara, baik sebelum atau setelah permintaan `TransactWriteItems`. Beberapa permintaan `GetItem`, terhadap kunci dalam permintaan `TransactWriteItems` bersamaan dapat dijalankan dalam urutan apa pun, dan karena itu hasilnya *read-committed*.

Misalnya, jika permintaan `GetItem` untuk item A dan item B dijalankan bersamaan dengan permintaan `TransactWriteItems` yang memodifikasi item A dan item B, ada empat kemungkinan:
+ Kedua permintaan `GetItem` dijalankan sebelum permintaan `TransactWriteItems`.
+ Kedua permintaan `GetItem` dijalankan setelah permintaan `TransactWriteItems`.
+ Permintaan `GetItem` untuk item A dijalankan sebelum permintaan `TransactWriteItems`. Untuk item B, `GetItem` dijalankan setelah `TransactWriteItems`.
+ Permintaan `GetItem` untuk item B dijalankan sebelum permintaan `TransactWriteItems`. Untuk item A, `GetItem` dijalankan setelah `TransactWriteItems`.

Anda harus menggunakan `TransactGetItems` jika Anda lebih suka tingkat isolasi serializable untuk beberapa permintaan. `GetItem`

Jika pembacaan non-transaksional dilakukan pada beberapa item yang merupakan bagian dari permintaan penulisan transaksi yang sama dalam penerbangan, Anda mungkin dapat membaca status baru dari beberapa item dan status lama item lainnya. Anda akan dapat membaca status baru dari semua item yang merupakan bagian dari permintaan tulis transaksi hanya ketika respons berhasil diterima untuk penulisan transaksional, yang menunjukkan bahwa transaksi telah selesai.

Setelah transaksi berhasil diselesaikan dan respons diterima, operasi baca yang *konsisten* selanjutnya mungkin masih mengembalikan status lama untuk waktu yang singkat karena model konsistensi DynamoDB akhirnya. Untuk menjamin membaca sebagian besar up-to-date data segera setelah transaksi, Anda harus menggunakan pembacaan yang [*sangat konsisten*](HowItWorks.ReadConsistency.md#HowItWorks.ReadConsistency.Strongly) dengan menyetel `ConsistentRead` ke true.

### READ-COMMITTED
<a name="transaction-isolation-read-committed"></a>

Isolasi *read-commit* memastikan bahwa operasi baca selalu mengembalikan komitmen untuk suatu item - pembacaan tidak akan pernah menampilkan tampilan ke item yang mewakili keadaan dari penulisan transaksional yang pada akhirnya tidak berhasil. Isolasi komitmen baca tidak mencegah modifikasi item segera setelah operasi baca.

Tingkat isolasi read-committed antara operasi transaksional dan operasi baca yang melibatkan beberapa baca standar (`BatchGetItem`, `Query`, atau `Scan`). Jika transaksional tulis memperbarui item di tengah operasi `BatchGetItem`, `Query`, atau `Scan`, bagian selanjutnya dari operasi baca mengembalikan nilai berkomitmen baru (dengan `ConsistentRead)` atau mungkin nilai berkomitmen sebelumnya (bacaan akhir konsisten).

### Ringkasan operasi
<a name="transaction-isolation-table"></a>

Untuk meringkas, tabel berikut menunjukkan tingkat isolasi antara operasi transaksi (`TransactWriteItems` atau `TransactGetItems`) dan operasi lainnya.


| Operasi | Tingkat Isolasi | 
| --- | --- | 
| `DeleteItem` | *Dapat diserialkan* | 
| `PutItem` | *Dapat diserialkan* | 
| `UpdateItem` | *Dapat diserialkan* | 
| `GetItem` | *Dapat diserialkan* | 
| `BatchGetItem` | *Read-committed*\$1 | 
| `BatchWriteItem` | *Tidak Dapat Diserialkan*\$1 | 
| `Query` | *Read-committed* | 
| `Scan` | *Read-committed* | 
| Operasi transaksional lainnya | *Dapat diserialkan* | 

Tingkat yang ditandai dengan tanda bintang (\$1) berlaku untuk operasi sebagai sebuah unit. Namun, tindakan individu dalam operasi tersebut memiliki tingkat isolasi yang *dapat diserialkan*.

## Penanganan konflik transaksi di DynamoDB
<a name="transaction-conflict-handling"></a>

Konflik transaksional dapat terjadi selama permintaan tingkat item bersamaan pada item dalam transaksi. Konflik transaksi dapat terjadi dalam skenario berikut: 
+ Permintaan `PutItem`, `UpdateItem`, atau `DeleteItem` untuk item yang bertentangan dengan permintaan `TransactWriteItems` yang sedang berlangsung yang mencakup item yang sama.
+ Item dalam permintaan `TransactWriteItems` adalah bagian dari permintaan `TransactWriteItems` lain yang sedang berlangsung.
+ Item dalam permintaan `TransactGetItems` adalah bagian dari permintaan `TransactWriteItems`, `BatchWriteItem`, `PutItem`, `UpdateItem`, atau `DeleteItem` yang sedang berlangsung.

**catatan**  
Saat permintaan `PutItem`, `UpdateItem`, atau `DeleteItem` ditolak, permintaan gagal dengan `TransactionConflictException`. 
Jika ada permintaan tingkat item dalam `TransactWriteItems` atau `TransactGetItems` ditolak, permintaan gagal dengan `TransactionCanceledException`. Jika permintaan itu gagal, AWS SDKs jangan coba lagi permintaan tersebut.  
Jika Anda menggunakan AWS SDK untuk Java, pengecualian berisi daftar [CancellationReasons](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_CancellationReason.html), diurutkan sesuai dengan daftar item dalam parameter `TransactItems` permintaan. Untuk bahasa lain, representasi string daftar disertakan dalam pesan kesalahan pengecualian. 
Jika operasi `TransactWriteItems` atau `TransactGetItems` yang sedang berlangsung bertentangan dengan permintaan `GetItem` bersamaan, kedua operasi dapat berhasil.

[TransactionConflict CloudWatch Metrik](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/metrics-dimensions.html) ditambahkan untuk setiap permintaan tingkat item yang gagal.

## Menggunakan transaksional di APIs DynamoDB Accelerator (DAX)
<a name="transaction-apis-dax"></a>

`TransactWriteItems` dan `TransactGetItems` keduanya didukung di DynamoDB Accelerator (DAX) dengan tingkat isolasi yang sama seperti di DynamoDB.

`TransactWriteItems` menulis melalui DAX. DAX menyampaikan panggilan `TransactWriteItems` ke DynamoDB dan mengembalikan respons. Untuk mempopulasi cache setelah menulis, DAX memanggil `TransactGetItems` di latar belakang untuk setiap item dalam operasi `TransactWriteItems`, yang mengonsumsi unit kapasitas baca tambahan. (Untuk informasi selengkapnya, lihat [Manajemen kapasitas untuk transaksi](#transaction-capacity-handling).) Fungsionalitas ini memungkinkan Anda untuk menjaga logika aplikasi Anda sederhana dan menggunakan DAX untuk kedua operasi transaksional dan nontransaksional.

Panggilan `TransactGetItems` disampaikan melalui DAX tanpa item di-cache secara lokal. Ini adalah perilaku yang sama dengan pembacaan yang sangat konsisten APIs di DAX.

## Manajemen kapasitas untuk transaksi
<a name="transaction-capacity-handling"></a>

Tidak ada biaya tambahan untuk mengaktifkan transaksi untuk tabel DynamoDB Anda. Anda hanya membayar untuk baca atau tulis yang merupakan bagian dari transaksi Anda. DynamoDB melakukan dua baca atau tulis mendasar dari setiap item dalam transaksi: satu untuk mempersiapkan transaksi dan satu untuk melakukan transaksi. Dua read/write operasi yang mendasarinya terlihat di CloudWatch metrik Amazon Anda.

Rencanakan untuk membaca dan menulis tambahan yang diperlukan oleh transaksional APIs ketika Anda menyediakan kapasitas ke tabel Anda. Misalnya, anggaplah aplikasi Anda menjalankan satu transaksi per detik, dan setiap transaksi menulis tiga item 500-byte dalam tabel Anda. Setiap item membutuhkan dua unit kapasitas tulis (WCUs): satu untuk mempersiapkan transaksi dan satu untuk melakukan transaksi. Oleh karena itu, Anda perlu menyediakan enam WCUs ke meja. 

Jika Anda menggunakan DynamoDB Accelerator (DAX) pada contoh sebelumnya, Anda juga akan menggunakan dua unit kapasitas baca RCUs () untuk setiap item dalam panggilan. `TransactWriteItems` Jadi, Anda perlu memberikan enam tambahan RCUs ke tabel.

Demikian pula, jika aplikasi Anda menjalankan satu transaksi baca per detik, dan setiap transaksi membaca tiga item 500 byte dalam tabel Anda, Anda perlu menyediakan enam unit kapasitas baca (RCUs) ke tabel. Membaca setiap item membutuhkan dua RCUs: satu untuk mempersiapkan transaksi dan satu untuk melakukan transaksi.

Selain itu, perilaku SDK default adalah untuk mencoba lagi transaksi dalam kasus pengecualian `TransactionInProgressException`. Rencanakan unit kapasitas baca tambahan (RCUs) yang dikonsumsi oleh percobaan ulang ini. Hal yang sama juga berlaku jika Anda mencoba ulang transaksi dalam kode Anda sendiri menggunakan `ClientRequestToken`.

## Praktik terbaik untuk transactions
<a name="transaction-best-practices"></a>

Pertimbangkan praktik yang disarankan berikut saat menggunakan DynamoDB Transactions.
+ Aktifkan penskalaan otomatis pada tabel Anda, atau pastikan bahwa Anda telah menyediakan kapasitas throughput yang cukup untuk melakukan dua operasi baca atau tulis untuk setiap item dalam transaksi Anda.
+ Jika Anda tidak menggunakan SDK yang AWS disediakan, sertakan `ClientRequestToken` atribut saat Anda melakukan `TransactWriteItems` panggilan untuk memastikan bahwa permintaan tersebut idempoten.
+ Jangan mengelompokkan operasi bersama-sama dalam sebuah transaksi jika tidak diperlukan. Misalnya, jika satu transaksi dengan 10 operasi dapat dipecah menjadi beberapa transaksi tanpa mengurangi kebenaran aplikasi, sebaiknya pisahkan transaksi tersebut. Transaksi yang lebih sederhana meningkatkan throughput dan lebih mungkin untuk berhasil. 
+ Beberapa transaksi memperbarui item yang sama secara bersamaan dapat menyebabkan konflik yang membatalkan transaksi. Kami merekomendasikan praktik terbaik DynamoDB berikut untuk pemodelan data untuk meminimalkan konflik tersebut.
+ Jika satu set atribut sering diperbarui di beberapa item sebagai bagian dari transaksi tunggal, pertimbangkan pengelompokan atribut menjadi satu item untuk mengurangi lingkup transaksi.
+ Hindari penggunaan transaksi untuk menyerap data secara massal. Untuk tulis massal, lebih baik menggunakan `BatchWriteItem`.

## Menggunakan transaksional APIs dengan tabel global
<a name="transaction-integration"></a>

Operasi transaksional memberikan jaminan atomisitas, konsistensi, isolasi, dan daya tahan (ACID) hanya di AWS Wilayah tempat API tulis dipanggil. Transaksi tidak didukung di seluruh Wilayah dalam tabel global. Misalnya, Anda memiliki tabel global dengan replika di Wilayah AS Timur (Ohio) dan AS Barat (Oregon) dan Anda melakukan operasi `TransactWriteItems` di Wilayah AS Timur (Virginia Utara). Anda dapat mengamati transaksi yang diselesaikan sebagian di Wilayah Barat AS (Oregon) saat perubahan direplikasi. Perubahan direplikasi ke Wilayah lain hanya setelah dilakukan di Wilayah sumber.

## Transaksi DynamoDB AWSLabs vs. perpustakaan klien transaksi
<a name="transaction-vs-library"></a>

Transaksi DynamoDB menyediakan penggantian yang lebih hemat biaya, kuat, dan berkinerja untuk pustaka klien transaksi. [AWSLabs](https://github.com/awslabs) Kami menyarankan agar Anda memperbarui aplikasi Anda untuk menggunakan transaksi asli, sisi server. APIs

# Menggunakan IAM dengan DynamoDB transactions
<a name="transaction-apis-iam"></a>

Anda dapat menggunakan AWS Identity and Access Management (IAM) untuk membatasi tindakan yang dapat dilakukan operasi transaksional di Amazon DynamoDB. Untuk informasi selengkapnya tentang menggunakan kebijakan IAM dalam DynamoDB, lihat [Kebijakan berbasis identitas untuk DynamoDB](security_iam_service-with-iam.md#security_iam_service-with-iam-id-based-policies).

Izin untuk tindakan `Put`, `Update`, `Delete`, dan `Get` diatur oleh izin yang digunakan untuk operasi `PutItem`, `UpdateItem`, `DeleteItem`, dan `GetItem` yang mendasarinya. Untuk tindakan `ConditionCheck`, Anda dapat menggunakan izin `dynamodb:ConditionCheckItem` dalam kebijakan IAM.

Berikut ini adalah contoh kebijakan IAM yang dapat Anda gunakan untuk mengonfigurasi DynamoDB transactions.

## Contoh 1: Mengizinkan operasi transaksional
<a name="tx-policy-example-1"></a>

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:ConditionCheckItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem",
                "dynamodb:GetItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:*:*:table/table04"
            ]
        }
    ]
}
```

------

## Contoh 2: Hanya mengizinkan operasi transaksional
<a name="tx-policy-example-2"></a>

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:ConditionCheckItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem",
                "dynamodb:GetItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:*:*:table/table04"
            ],
            "Condition": {
                "ForAnyValue:StringEquals": {
                    "dynamodb:EnclosingOperation": [
                        "TransactWriteItems",
                        "TransactGetItems"
                    ]
                }
            }
        }
    ]
}
```

------

## Contoh 3: Mengizinkan baca dan tulis nontransaksional, dan memblokir baca dan tulis transaksional
<a name="tx-policy-example-3"></a>

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Deny",
            "Action": [
                "dynamodb:ConditionCheckItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem",
                "dynamodb:GetItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:*:*:table/table04"
            ],
            "Condition": {
                "ForAnyValue:StringEquals": {
                    "dynamodb:EnclosingOperation": [
                        "TransactWriteItems",
                        "TransactGetItems"
                    ]
                }
            }
        },
        {
            "Effect": "Allow",
             "Action": [
                 "dynamodb:PutItem",
                 "dynamodb:DeleteItem",
                 "dynamodb:GetItem",
                 "dynamodb:UpdateItem"
             ],
             "Resource": [
                 "arn:aws:dynamodb:*:*:table/table04"
             ]
         }
    ]
}
```

------

## Contoh 4: Mencegah informasi dikembalikan pada ConditionCheck kegagalan
<a name="tx-policy-example-4"></a>

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:ConditionCheckItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem",
                "dynamodb:GetItem"
            ],
            "Resource": "arn:aws:dynamodb:*:*:table/table01",
            "Condition": {
                "StringEqualsIfExists": {
                    "dynamodb:ReturnValues": "NONE"
                }
            }
        }
    ]
}
```

------

# Contoh DynamoDB transactions
<a name="transaction-example"></a>

Sebagai contoh situasi di mana Amazon DynamoDB transactions dapat berguna, pertimbangkan contoh aplikasi Java untuk marketplace online ini.

Aplikasi ini memiliki tiga tabel DynamoDB di backend:
+ `Customers` — Tabel ini menyimpan detail tentang pelanggan marketplace. Kunci primernya adalah pengidentifikasi unik `CustomerId`.
+ `ProductCatalog` — Tabel ini menyimpan detail seperti harga dan ketersediaan produk yang dijual di marketplace. Kunci primernya adalah pengidentifikasi unik `ProductId`.
+ `Orders` — Tabel ini menyimpan detail pesanan dari marketplace. Kunci primernya adalah pengidentifikasi unik `OrderId`.

## Membuat pesanan
<a name="transaction-example-write-order"></a>

Potongan kode berikut menggambarkan cara menggunakan DynamoDB transaction untuk mengoordinasikan beberapa langkah yang diperlukan untuk membuat dan memproses pesanan. Menggunakan satu all-or-nothing operasi memastikan bahwa jika ada bagian dari transaksi yang gagal, tidak ada tindakan dalam transaksi yang dijalankan dan tidak ada perubahan yang dilakukan.

Dalam contoh ini, Anda menyiapkan pesanan dari pelanggan yang `customerId` adalah `09e8e9c8-ec48`. Anda kemudian menjalankannya sebagai satu transaksi menggunakan alur kerja pemrosesan pesanan sederhana berikut:

1. Tentukan apakah ID pelanggan valid.

1. Pastikan produk `IN_STOCK`, dan perbarui status produk menjadi `SOLD`.

1. Pastikan pesanan belum ada, lalu buat pesanan.

### Memvalidasi pelanggan
<a name="transaction-example-order-part-a"></a>

Pertama, tentukan tindakan untuk memverifikasi bahwa pelanggan dengan `customerId` sama dengan `09e8e9c8-ec48` ada di tabel pelanggan.

```
final String CUSTOMER_TABLE_NAME = "Customers";
final String CUSTOMER_PARTITION_KEY = "CustomerId";
final String customerId = "09e8e9c8-ec48";
final HashMap<String, AttributeValue> customerItemKey = new HashMap<>();
customerItemKey.put(CUSTOMER_PARTITION_KEY, new AttributeValue(customerId));

ConditionCheck checkCustomerValid = new ConditionCheck()
    .withTableName(CUSTOMER_TABLE_NAME)
    .withKey(customerItemKey)
    .withConditionExpression("attribute_exists(" + CUSTOMER_PARTITION_KEY + ")");
```

### Memperbarui status produk
<a name="transaction-example-order-part-b"></a>

Selanjutnya, tentukan tindakan untuk memperbarui status produk menjadi `SOLD` jika kondisi status produk saat ini diatur ke `IN_STOCK` `true`. Mengatur parameter `ReturnValuesOnConditionCheckFailure` akan mengembalikan item jika atribut status produk item tidak sama dengan `IN_STOCK`.

```
final String PRODUCT_TABLE_NAME = "ProductCatalog";
final String PRODUCT_PARTITION_KEY = "ProductId";
HashMap<String, AttributeValue> productItemKey = new HashMap<>();
productItemKey.put(PRODUCT_PARTITION_KEY, new AttributeValue(productKey));

Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
expressionAttributeValues.put(":new_status", new AttributeValue("SOLD"));
expressionAttributeValues.put(":expected_status", new AttributeValue("IN_STOCK"));

Update markItemSold = new Update()
    .withTableName(PRODUCT_TABLE_NAME)
    .withKey(productItemKey)
    .withUpdateExpression("SET ProductStatus = :new_status")
    .withExpressionAttributeValues(expressionAttributeValues)
    .withConditionExpression("ProductStatus = :expected_status")
    .withReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD);
```

### Membuat pesanan
<a name="transaction-example-order-part-c"></a>

Terakhir, buat pesanan selama pesanan dengan `OrderId` tersebut belum ada.

```
final String ORDER_PARTITION_KEY = "OrderId";
final String ORDER_TABLE_NAME = "Orders";

HashMap<String, AttributeValue> orderItem = new HashMap<>();
orderItem.put(ORDER_PARTITION_KEY, new AttributeValue(orderId));
orderItem.put(PRODUCT_PARTITION_KEY, new AttributeValue(productKey));
orderItem.put(CUSTOMER_PARTITION_KEY, new AttributeValue(customerId));
orderItem.put("OrderStatus", new AttributeValue("CONFIRMED"));
orderItem.put("OrderTotal", new AttributeValue("100"));

Put createOrder = new Put()
    .withTableName(ORDER_TABLE_NAME)
    .withItem(orderItem)
    .withReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
    .withConditionExpression("attribute_not_exists(" + ORDER_PARTITION_KEY + ")");
```

### Menjalankan transaksi
<a name="transaction-example-order-part-d"></a>

Contoh berikut menggambarkan bagaimana menjalankan tindakan yang didefinisikan sebelumnya sebagai all-or-nothing operasi tunggal.

```
    Collection<TransactWriteItem> actions = Arrays.asList(
        new TransactWriteItem().withConditionCheck(checkCustomerValid),
        new TransactWriteItem().withUpdate(markItemSold),
        new TransactWriteItem().withPut(createOrder));

    TransactWriteItemsRequest placeOrderTransaction = new TransactWriteItemsRequest()
        .withTransactItems(actions)
        .withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);

    // Run the transaction and process the result.
    try {
        client.transactWriteItems(placeOrderTransaction);
        System.out.println("Transaction Successful");

    } catch (ResourceNotFoundException rnf) {
        System.err.println("One of the table involved in the transaction is not found" + rnf.getMessage());
    } catch (InternalServerErrorException ise) {
        System.err.println("Internal Server Error" + ise.getMessage());
    } catch (TransactionCanceledException tce) {
        System.out.println("Transaction Canceled " + tce.getMessage());
    }
```

## Membaca detail pesanan
<a name="transaction-example-read-order"></a>

Contoh berikut menunjukkan cara membaca pesanan yang telah selesai secara transaksional di seluruh tabel `Orders` dan `ProductCatalog`.

```
HashMap<String, AttributeValue> productItemKey = new HashMap<>();
productItemKey.put(PRODUCT_PARTITION_KEY, new AttributeValue(productKey));

HashMap<String, AttributeValue> orderKey = new HashMap<>();
orderKey.put(ORDER_PARTITION_KEY, new AttributeValue(orderId));

Get readProductSold = new Get()
    .withTableName(PRODUCT_TABLE_NAME)
    .withKey(productItemKey);
Get readCreatedOrder = new Get()
    .withTableName(ORDER_TABLE_NAME)
    .withKey(orderKey);

Collection<TransactGetItem> getActions = Arrays.asList(
    new TransactGetItem().withGet(readProductSold),
    new TransactGetItem().withGet(readCreatedOrder));

TransactGetItemsRequest readCompletedOrder = new TransactGetItemsRequest()
    .withTransactItems(getActions)
    .withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);

// Run the transaction and process the result.
try {
    TransactGetItemsResult result = client.transactGetItems(readCompletedOrder);
    System.out.println(result.getResponses());
} catch (ResourceNotFoundException rnf) {
    System.err.println("One of the table involved in the transaction is not found" + rnf.getMessage());
} catch (InternalServerErrorException ise) {
    System.err.println("Internal Server Error" + ise.getMessage());
} catch (TransactionCanceledException tce) {
    System.err.println("Transaction Canceled" + tce.getMessage());
}
```

# Tangkapan data perubahan dengan Amazon DynamoDB
<a name="streamsmain"></a>

Banyak aplikasi mendapatkan manfaat dari menangkap perubahan ke item yang disimpan dalam tabel DynamoDB pada titik waktu ketika perubahan terjadi. Berikut adalah beberapa contoh kasus penggunaan:
+ Sebuah aplikasi seluler populer memodifikasi data dalam tabel DynamoDB, pada tingkat ribuan pembaruan per detik. Aplikasi lain menangkap dan menyimpan data tentang pembaruan ini, menyediakan metrik near-real-time penggunaan untuk aplikasi seluler.
+ Sebuah aplikasi keuangan memodifikasi data pasar saham dalam tabel DynamoDB. Berbagai aplikasi yang berjalan secara paralel melacak perubahan ini secara real time, menghitung value-at-risk, dan secara otomatis menyeimbangkan portofolio berdasarkan pergerakan harga saham.
+ Sensor dalam kendaraan transportasi dan peralatan industri mengirim data ke meja DynamoDB. Aplikasi yang berbeda memantau kinerja dan mengirim pesan peringatan ketika masalah terdeteksi, memprediksi potensi cacat dengan menerapkan algoritma machine learning, dan mengompres serta mengarsip data ke Amazon Simple Storage Service (Amazon S3).
+ Sebuah aplikasi secara otomatis mengirimkan pemberitahuan ke perangkat seluler dari semua teman dalam grup segera setelah satu teman mengunggah gambar baru.
+ Seorang pelanggan baru menambahkan data ke tabel DynamoDB. Acara ini memanggil aplikasi lain yang mengirimkan email selamat datang ke pelanggan baru.

DynamoDB mendukung streaming catatan tangkapan data perubahan tingkat item yang dalam hampir waktu nyata. Anda dapat membangun aplikasi yang mengkonsumsi stream ini dan mengambil tindakan berdasarkan isinya.

**catatan**  
Menambahkan tag ke DynamoDB Streams dan [menggunakan kontrol akses berbasis atribut (ABAC)](access-control-resource-based.md) dengan DynamoDB Streams tidak didukung.

Video berikut akan memberi Anda tampilan pengantar tentang konsep pengambilan data perubahan.

[![AWS Videos](http://img.youtube.com/vi/https://www.youtube.com/embed/VVv_-mZ5Ge8/0.jpg)](http://www.youtube.com/watch?v=https://www.youtube.com/embed/VVv_-mZ5Ge8)


**Topics**
+ [Opsi streaming untuk tangkapan data perubahan](#streamsmain.choose)
+ [Menggunakan Kinesis Data Streams untuk menangkap perubahan pada DynamoDB](kds.md)
+ [Tangkapan data perubahan DynamoDB Streams](Streams.md)

## Opsi streaming untuk tangkapan data perubahan
<a name="streamsmain.choose"></a>

DynamoDB menawarkan dua model streaming untuk penangkapan data perubahan: Kinesis Data Streams untuk DynamoDB dan DynamoDB Streams.

Untuk membantu Anda memilih solusi yang tepat untuk aplikasi Anda, tabel berikut merangkum fitur dari setiap model streaming. 

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/streamsmain.html)

Anda dapat mengaktifkan kedua model streaming pada tabel DynamoDB yang sama.

Video berikut berbicara lebih banyak tentang perbedaan antara dua opsi tersebut.

[![AWS Videos](http://img.youtube.com/vi/https://www.youtube.com/embed/UgG17Wh2y0g/0.jpg)](http://www.youtube.com/watch?v=https://www.youtube.com/embed/UgG17Wh2y0g)


# Menggunakan Kinesis Data Streams untuk menangkap perubahan pada DynamoDB
<a name="kds"></a>

Gunakan Amazon Kinesis Data Streams untuk menangkap perubahan pada Amazon DynamoDB.

Kinesis Data Streams menangkap modifikasi tingkat item di tabel DynamoDB apa pun dan mereplikasikannya ke [Kinesis data stream.](https://docs.aws.amazon.com/streams/latest/dev/introduction.html) Aplikasi Anda dapat mengakses stream ini dan melihat perubahan tingkat item dalam hampir waktu nyata. Anda dapat terus menangkap dan menyimpan data berukuran terabyte per jam. Anda dapat memanfaatkan waktu retensi data yang lebih lama—dan dengan kemampuan fan-out yang ditingkatkan, Anda dapat menjangkau dua atau lebih aplikasi hilir secara bersamaan. Manfaat lainnya termasuk audit tambahan dan transparansi keamanan.

Kinesis Data Streams juga memberi Anda akses [ke Amazon Data [Firehose dan Amazon](https://docs.aws.amazon.com/kinesisanalytics/latest/dev/what-is.html) Managed](https://docs.aws.amazon.com/firehose/latest/dev/what-is-this-service.html) Service untuk Apache Flink. Layanan ini dapat membantu Anda membangun aplikasi yang mendukung dasbor real-time, menghasilkan peringatan, menerapkan penetapan harga dan periklanan dinamis, serta menerapkan analitik data dan algoritma machine learning yang canggih.

**catatan**  
[Menggunakan aliran data Kinesis untuk DynamoDB tunduk pada harga Kinesis Data Streams untuk aliran data dan [harga DynamoDB untuk tabel sumber](https://aws.amazon.com/kinesis/data-streams/pricing/).](https://aws.amazon.com/dynamodb/pricing/)

Untuk mengaktifkan Kinesis streaming pada tabel DynamoDB menggunakan konsol, atau Java SDK AWS CLI, lihat. [Memulai Kinesis Data Streams untuk Amazon DynamoDB](kds_gettingstarted.md)

**Topics**
+ [Cara kerja Kinesis Data Streams dengan DynamoDB](#kds_howitworks)
+ [Memulai Kinesis Data Streams untuk Amazon DynamoDB](kds_gettingstarted.md)
+ [Menggunakan pecahan dan metrik dengan DynamoDB Streams dan Kinesis Data Streams](kds_using-shards-and-metrics.md)
+ [Menggunakan kebijakan IAM untuk Amazon Kinesis Data Streams dan Amazon DynamoDB](kds_iam.md)

## Cara kerja Kinesis Data Streams dengan DynamoDB
<a name="kds_howitworks"></a>

Ketika aliran data Kinesis diaktifkan untuk tabel DynamoDB, tabel mengirimkan rekaman data yang mencatat perubahan apa pun pada data tabel tersebut. Catatan data ini meliputi:
+ Waktu spesifik item mana pun baru saja dibuat, diperbarui, atau dihapus
+ Kunci utama item itu
+ Cuplikan catatan sebelum modifikasi
+ Cuplikan catatan setelah modifikasi 

Catatan data ini diambil dan dipublikasikan hampir secara waktu nyata. Setelah ditulis ke aliran data Kinesis, data tersebut dapat dibaca seperti catatan lainnya. Anda dapat menggunakan Kinesis Client Library, menggunakan AWS Lambda, memanggil Kinesis Data Streams API, dan menggunakan layanan terhubung lainnya. Untuk informasi selengkapnya, lihat [Membaca Data dari Amazon Kinesis Data Streams](https://docs.aws.amazon.com/streams/latest/dev/building-consumers.html) dalam Panduan Developer Amazon Kinesis Data Streams.

Perubahan pada data ini juga ditangkap secara asinkron. Kinesis tidak memiliki dampak kinerja pada tabel asal streamingnya. Catatan aliran yang disimpan dalam aliran data Kinesis Anda juga dienkripsi saat tidak digunakan. Untuk informasi selengkapnya, lihat [Perlindungan Data di Amazon Kinesis Data Streams](https://docs.aws.amazon.com/streams/latest/dev/server-side-encryption.html).

Catatan aliran data Kinesis mungkin muncul dalam urutan yang berbeda dari saat perubahan item terjadi. Notifikasi item yang sama mungkin juga muncul lebih dari satu kali di aliran. Anda dapat memeriksa `ApproximateCreationDateTime` atribut untuk mengidentifikasi urutan modifikasi item terjadi, dan untuk mengidentifikasi catatan duplikat. 

Saat Anda mengaktifkan aliran data Kinesis sebagai tujuan streaming tabel DynamoDB, Anda dapat mengonfigurasi presisi `ApproximateCreationDateTime` nilai dalam milidetik atau mikrodetik. Secara default, `ApproximateCreationDateTime` menunjukkan waktu perubahan dalam milidetik. Selain itu, Anda dapat mengubah nilai ini di tujuan streaming aktif. Setelah pembaruan seperti itu, catatan aliran yang ditulis ke Kinesis akan memiliki `ApproximateCreationDateTime` nilai presisi yang diinginkan. 

Nilai biner yang ditulis ke DynamoDB harus dikodekan dalam [format berenkode base64](HowItWorks.NamingRulesDataTypes.md) . Namun, ketika catatan data ditulis ke aliran data Kinesis, nilai biner yang dikodekan ini dikodekan dengan pengodean base64 untuk kedua kalinya. Saat membaca catatan ini dari aliran data Kinesis, untuk mengambil nilai biner mentah, aplikasi harus mendekode nilai ini dua kali.

DynamoDB mengenakan biaya untuk penggunaan Kinesis Data Streams dalam unit pengambilan data perubahan. Perubahan 1 KB per item dihitung sebagai satu unit pengambilan data perubahan. KB perubahan di setiap item dihitung berdasarkan gambar "sebelum" dan "sesudah" yang lebih besar dari item yang ditulis ke aliran, menggunakan logika yang sama dengan [konsumsi unit kapasitas untuk operasi tulis](read-write-operations.md#write-operation-consumption). Mirip dengan bagaimana mode DynamoDB [sesuai permintaan](capacity-mode.md#capacity-mode-on-demand) bekerja, Anda tidak perlu menyediakan throughput kapasitas untuk unit penangkapan data perubahan.

### Mengaktifkan aliran data Kinesis untuk tabel DynamoDB Anda
<a name="kds_howitworks.enabling"></a>

Anda dapat mengaktifkan atau menonaktifkan streaming ke Kinesis dari tabel DynamoDB yang ada dengan menggunakan, AWS SDK Konsol Manajemen AWS, atau (). AWS Command Line Interface AWS CLI
+ Anda hanya dapat mengalirkan data dari DynamoDB ke Kinesis Data Streams di AWS akun dan Wilayah yang sama dengan tabel Anda. AWS 
+ Anda hanya dapat melakukan streaming data dari tabel DynamoDB ke satu Kinesis data stream.

  

### Membuat perubahan pada tujuan Kinesis Data Streams pada tabel DynamoDB
<a name="kds_howitworks.makingchanges"></a>

Secara default, semua catatan aliran data Kinesis menyertakan atribut`ApproximateCreationDateTime`. Atribut ini mewakili stempel waktu dalam milidetik dari perkiraan waktu ketika setiap rekaman dibuat. Anda dapat mengubah presisi nilai-nilai ini dengan menggunakan [https://console.aws.amazon.com/kinesis](https://console.aws.amazon.com/kinesis), SDK atau AWS CLI 

# Memulai Kinesis Data Streams untuk Amazon DynamoDB
<a name="kds_gettingstarted"></a>

Bagian ini menjelaskan cara menggunakan Kinesis Data Streams untuk tabel Amazon DynamoDB dengan konsol Amazon AWS Command Line Interface AWS CLI DynamoDB, (), dan API.

## Membuat aliran data Amazon Kinesis yang aktif
<a name="kds_gettingstarted.making-changes"></a>

Semua contoh ini menggunakan tabel `Music` DynamoDB yang dibuat sebagai bagian dari tutorial [Memulai dengan DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStartedDynamoDB.html).

Untuk mempelajari lebih lanjut tentang cara membangun konsumen dan menghubungkan aliran data Kinesis Anda ke layanan AWS lain, lihat [Membaca data dari Kinesis Data Streams](https://docs.aws.amazon.com/streams/latest/dev/building-consumers.html) dalam *panduan pengembang Amazon Kinesis Data Streams*.

**catatan**  
 Saat Anda pertama kali menggunakan serpihan KDS, sebaiknya atur serpihan Anda untuk ditingkatkan dan diturunkan skalanya sesuai dengan pola penggunaan. Setelah mengumpulkan lebih banyak data tentang pola penggunaan, Anda dapat menyesuaikan serpihan di aliran agar sesuai. 

------
#### [ Console ]

1. Masuk ke Konsol Manajemen AWS dan buka konsol Kinesis di. [https://console.aws.amazon.com/kinesis/](https://console.aws.amazon.com/kinesis/)

1. Pilih **Buat aliran data** dan ikuti petunjuk untuk membuat stream yang disebut `samplestream`. 

1. Buka konsol DynamoDB di. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Di panel navigasi di sisi kiri konsol, pilih **Tabel**.

1. Pilih tabel **Musik**.

1. Pilih tab **Ekspor dan aliran**.

1. (Opsional) Di bawah **detail aliran data Amazon Kinesis**, Anda dapat mengubah presisi stempel waktu rekaman dari mikrodetik (default) menjadi milidetik. 

1. Pilih **samplestream** dari daftar menurun.

1. Pilih tombol **Hidupkan**.

------
#### [ AWS CLI ]

1. Buat Kinesis Data Streams bernama `samplestream` dengan menggunakan [perintah create-stream](https://docs.aws.amazon.com/cli/latest/reference/kinesis/create-stream.html).

   ```
   aws kinesis create-stream --stream-name samplestream --shard-count 3 
   ```

   Lihat [Pertimbangan manajemen pecahan untuk Kinesis Data Streams](kds_using-shards-and-metrics.md#kds_using-shards-and-metrics.shardmanagment) sebelum menetapkan jumlah serpihan untuk Kinesis data stream.

1. Periksa apakah stream Kinesis aktif dan siap digunakan dengan menggunakan [perintah describe-stream](https://docs.aws.amazon.com/cli/latest/reference/kinesis/describe-stream.html).

   ```
   aws kinesis describe-stream --stream-name samplestream
   ```

1. Aktifkan Kinesis streaming pada tabel DynamoDB dengan menggunakan perintah `enable-kinesis-streaming-destination` DynamoDB. Ganti `stream-arn` nilai dengan yang ditampilkan `describe-stream` pada langkah sebelumnya. Secara opsional, aktifkan streaming dengan presisi nilai stempel waktu yang lebih granular (mikrodetik) yang dikembalikan pada setiap catatan.

   Aktifkan streaming dengan presisi stempel waktu mikrodetik:

   ```
   aws dynamodb enable-kinesis-streaming-destination \
     --table-name Music \
     --stream-arn arn:aws:kinesis:us-west-2:12345678901:stream/samplestream
     --enable-kinesis-streaming-configuration ApproximateCreationDateTimePrecision=MICROSECOND
   ```

   Atau aktifkan streaming dengan presisi stempel waktu default (milidetik):

   ```
   aws dynamodb enable-kinesis-streaming-destination \
     --table-name Music \
     --stream-arn arn:aws:kinesis:us-west-2:12345678901:stream/samplestream
   ```

1. Periksa apakah streaming Kinesis aktif pada tabel DynamoDB dengan menggunakan perintah `describe-kinesis-streaming-destination` DynamoDB.

   ```
   aws dynamodb describe-kinesis-streaming-destination --table-name Music
   ```

1. Menulis data ke Daftar Tabel DynamoDB dengan menggunakan perintah `put-item`, seperti yang dijelaskan dalam [Panduan Developer DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/getting-started-step-2.html).

   ```
   aws dynamodb put-item \
       --table-name Music  \
       --item \
           '{"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Call Me Today"}, "AlbumTitle": {"S": "Somewhat Famous"}, "Awards": {"N": "1"}}'
   
   aws dynamodb put-item \
       --table-name Music \
       --item \
           '{"Artist": {"S": "Acme Band"}, "SongTitle": {"S": "Happy Day"}, "AlbumTitle": {"S": "Songs About Life"}, "Awards": {"N": "10"} }'
   ```

1. Gunakan perintah CLI Kinesis [get-records](https://docs.aws.amazon.com/cli/latest/reference/kinesis/get-records.html) untuk mengambil konten stream Kinesis. Kemudian gunakan potongan kode berikut untuk melakukan deserialisasi konten stream.

   ```
   /**
    * Takes as input a Record fetched from Kinesis and does arbitrary processing as an example.
    */
   public void processRecord(Record kinesisRecord) throws IOException {
       ByteBuffer kdsRecordByteBuffer = kinesisRecord.getData();
       JsonNode rootNode = OBJECT_MAPPER.readTree(kdsRecordByteBuffer.array());
       JsonNode dynamoDBRecord = rootNode.get("dynamodb");
       JsonNode oldItemImage = dynamoDBRecord.get("OldImage");
       JsonNode newItemImage = dynamoDBRecord.get("NewImage");
       Instant recordTimestamp = fetchTimestamp(dynamoDBRecord);
   
       /**
        * Say for example our record contains a String attribute named "stringName" and we want to fetch the value
        * of this attribute from the new item image. The following code fetches this value.
        */
       JsonNode attributeNode = newItemImage.get("stringName");
       JsonNode attributeValueNode = attributeNode.get("S"); // Using DynamoDB "S" type attribute
       String attributeValue = attributeValueNode.textValue();
       System.out.println(attributeValue);
   }
   
   private Instant fetchTimestamp(JsonNode dynamoDBRecord) {
       JsonNode timestampJson = dynamoDBRecord.get("ApproximateCreationDateTime");
       JsonNode timestampPrecisionJson = dynamoDBRecord.get("ApproximateCreationDateTimePrecision");
       if (timestampPrecisionJson != null && timestampPrecisionJson.equals("MICROSECOND")) {
           return Instant.EPOCH.plus(timestampJson.longValue(), ChronoUnit.MICROS);
       }
       return Instant.ofEpochMilli(timestampJson.longValue());
   }
   ```

------
#### [ Java ]

1. Ikuti petunjuk dalam panduan developer Kinesis Data Streams untuk [menciptakan](https://docs.aws.amazon.com/streams/latest/dev/kinesis-using-sdk-java-create-stream.html) Kinesis data stream bernama `samplestream` menggunakan Java.

   Lihat [Pertimbangan manajemen pecahan untuk Kinesis Data Streams](kds_using-shards-and-metrics.md#kds_using-shards-and-metrics.shardmanagment) sebelum menetapkan jumlah serpihan untuk Kinesis data stream. 

1. Gunakan cuplikan kode berikut untuk mengaktifkan Kinesis streaming pada tabel DynamoDB. Secara opsional, aktifkan streaming dengan presisi nilai stempel waktu yang lebih granular (mikrodetik) yang dikembalikan pada setiap catatan. 

   Aktifkan streaming dengan presisi stempel waktu mikrodetik:

   ```
   EnableKinesisStreamingConfiguration enableKdsConfig = EnableKinesisStreamingConfiguration.builder()
     .approximateCreationDateTimePrecision(ApproximateCreationDateTimePrecision.MICROSECOND)
     .build();
   
   EnableKinesisStreamingDestinationRequest enableKdsRequest = EnableKinesisStreamingDestinationRequest.builder()
     .tableName(tableName)
     .streamArn(kdsArn)
     .enableKinesisStreamingConfiguration(enableKdsConfig)
     .build();
   
   EnableKinesisStreamingDestinationResponse enableKdsResponse = ddbClient.enableKinesisStreamingDestination(enableKdsRequest);
   ```

   Atau aktifkan streaming dengan presisi stempel waktu default (milidetik):

   ```
   EnableKinesisStreamingDestinationRequest enableKdsRequest = EnableKinesisStreamingDestinationRequest.builder()
     .tableName(tableName)
     .streamArn(kdsArn)
     .build();
   
   EnableKinesisStreamingDestinationResponse enableKdsResponse = ddbClient.enableKinesisStreamingDestination(enableKdsRequest);
   ```

1. Ikuti instruksi dalam panduan pengembang *Kinesis Data Streams* untuk [membaca](https://docs.aws.amazon.com/streams/latest/dev/building-consumers.html) dari aliran data yang dibuat.

1. Gunakan potongan kode berikut untuk melakukan deserialisasi konten stream

   ```
   /**
    * Takes as input a Record fetched from Kinesis and does arbitrary processing as an example.
    */
   public void processRecord(Record kinesisRecord) throws IOException {
       ByteBuffer kdsRecordByteBuffer = kinesisRecord.getData();
       JsonNode rootNode = OBJECT_MAPPER.readTree(kdsRecordByteBuffer.array());
       JsonNode dynamoDBRecord = rootNode.get("dynamodb");
       JsonNode oldItemImage = dynamoDBRecord.get("OldImage");
       JsonNode newItemImage = dynamoDBRecord.get("NewImage");
       Instant recordTimestamp = fetchTimestamp(dynamoDBRecord);
   
       /**
        * Say for example our record contains a String attribute named "stringName" and we wanted to fetch the value
        * of this attribute from the new item image, the below code would fetch this.
        */
       JsonNode attributeNode = newItemImage.get("stringName");
       JsonNode attributeValueNode = attributeNode.get("S"); // Using DynamoDB "S" type attribute
       String attributeValue = attributeValueNode.textValue();
       System.out.println(attributeValue);
   }
   
   private Instant fetchTimestamp(JsonNode dynamoDBRecord) {
       JsonNode timestampJson = dynamoDBRecord.get("ApproximateCreationDateTime");
       JsonNode timestampPrecisionJson = dynamoDBRecord.get("ApproximateCreationDateTimePrecision");
       if (timestampPrecisionJson != null && timestampPrecisionJson.equals("MICROSECOND")) {
           return Instant.EPOCH.plus(timestampJson.longValue(), ChronoUnit.MICROS);
       }
       return Instant.ofEpochMilli(timestampJson.longValue());
   }
   ```

------

## Membuat perubahan pada aliran data Amazon Kinesis yang aktif
<a name="kds_gettingstarted.making-changes"></a>

Bagian ini menjelaskan cara membuat perubahan pada Kinesis Data Streams aktif untuk penyiapan DynamoDB dengan menggunakan konsol, dan API. AWS CLI 

**Konsol Manajemen AWS**

1. Buka konsol DynamoDB di [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Pergi ke meja Anda.

1. Pilih **Ekspor dan Aliran**.

**AWS CLI**

1. Hubungi `describe-kinesis-streaming-destination` untuk mengonfirmasi bahwa streaming tersebut`ACTIVE`. 

1. Panggilan`UpdateKinesisStreamingDestination`, seperti dalam contoh ini:

   ```
   aws dynamodb update-kinesis-streaming-destination --table-name enable_test_table --stream-arn arn:aws:kinesis:us-east-1:12345678901:stream/enable_test_stream --update-kinesis-streaming-configuration ApproximateCreationDateTimePrecision=MICROSECOND
   ```

1. Hubungi `describe-kinesis-streaming-destination` untuk mengonfirmasi bahwa streaming tersebut`UPDATING`.

1. Panggil `describe-kinesis-streaming-destination` secara berkala hingga status streaming `ACTIVE` kembali. Biasanya diperlukan waktu hingga 5 menit agar pembaruan presisi stempel waktu diterapkan. Setelah status ini diperbarui, itu menunjukkan bahwa pembaruan selesai dan nilai presisi baru akan diterapkan pada catatan masa depan.

1. Tulis ke meja menggunakan`putItem`.

1. Gunakan `get-records` perintah Kinesis untuk mendapatkan konten aliran.

1. Konfirmasikan bahwa penulisan memiliki presisi yang diinginkan. `ApproximateCreationDateTime`

**API Java**

1. Berikan cuplikan kode yang membuat `UpdateKinesisStreamingDestination` permintaan dan respons. `UpdateKinesisStreamingDestination` 

1. Berikan cuplikan kode yang membuat `DescribeKinesisStreamingDestination` permintaan dan file. `DescribeKinesisStreamingDestination response`

1. Panggil `describe-kinesis-streaming-destination` secara berkala hingga status streaming `ACTIVE` kembali, menunjukkan bahwa pembaruan selesai dan nilai presisi baru akan diterapkan pada catatan masa depan.

1. Lakukan menulis ke meja.

1.  Baca dari aliran dan deserialisasi konten streaming.

1. Konfirmasikan bahwa penulisan memiliki presisi yang diinginkan. `ApproximateCreationDateTime`

# Menggunakan pecahan dan metrik dengan DynamoDB Streams dan Kinesis Data Streams
<a name="kds_using-shards-and-metrics"></a>

## Pertimbangan manajemen pecahan untuk Kinesis Data Streams
<a name="kds_using-shards-and-metrics.shardmanagment"></a>

Kinesis data strea, menghitung throughputnya dalam [pecahan](https://docs.aws.amazon.com/streams/latest/dev/key-concepts.html). Di Amazon Kinesis Data stream, Anda dapat memilih antara mode **sesuai permintaan** dan mode yang **disediakan** untuk aliran data Anda. 

Sebaiknya gunakan mode sesuai permintaan untuk Kinesis Data Stream Anda jika beban kerja penulisan DynamoDB Anda sangat bervariasi dan tidak dapat diprediksi. Dengan mode on-demand, tidak ada perencanaan kapasitas yang diperlukan karena Kinesis Data Streams secara otomatis mengelola pecahan untuk menyediakan throughput yang diperlukan.

Untuk beban kerja yang dapat diprediksi, Anda dapat menggunakan mode yang disediakan untuk Kinesis Data Stream Anda. Dengan mode yang disediakan, Anda harus menentukan jumlah pecahan untuk aliran data untuk mengakomodasi catatan pengambilan data perubahan dari DynamoDB. Untuk menentukan jumlah pecahan yang dibutuhkan aliran data Kinesis untuk mendukung tabel DynamoDB Anda, Anda memerlukan nilai input berikut:
+ Ukuran rata-rata catatan tabel DynamoDB Anda dalam byte (`average_record_size_in_bytes`).
+ Jumlah maksimum operasi tulis yang tabel DynamoDB Anda akan melakukan per detik. Ini termasuk membuat, menghapus, dan memperbarui operasi yang dilakukan oleh aplikasi Anda, serta operasi yang dihasilkan secara otomatis seperti Time to Live generated delete operations (`write_throughput`).
+ Persentase operasi pembaruan dan penimpaan yang Anda lakukan pada tabel Anda, dibandingkan dengan membuat atau menghapus operasi (`percentage_of_updates`). Perlu diingat bahwa operasi pembaruan dan penimpaan mereplikasi gambar lama dan baru dari item yang dimodifikasi ke stream. Ini menghasilkan dua kali ukuran item DynamoDB.

Anda dapat menghitung jumlah pecahan (`number_of_shards`) yang dibutuhkan aliran data Kinesis Anda dengan menggunakan nilai input dalam rumus berikut:

```
number_of_shards = ceiling( max( ((write_throughput * (4+percentage_of_updates) * average_record_size_in_bytes) / 1024 / 1024), (write_throughput/1000)), 1)
```

Misalnya, Anda mungkin memiliki throughput maksimum 1040 operasi tulis per detik (`write_throughput`) dengan ukuran catatan rata-rata 800 byte (. `average_record_size_in_bytes)` Jika 25 persen dari operasi penulisan tersebut adalah operasi pembaruan (`percentage_of_updates`), maka Anda akan memerlukan dua pecahan (`number_of_shards`) untuk mengakomodasi throughput streaming DynamoDB Anda:

```
ceiling( max( ((1040 * (4+25/100) * 800)/ 1024 / 1024), (1040/1000)), 1).
```

Pertimbangkan hal berikut sebelum menggunakan rumus untuk menghitung jumlah pecahan yang diperlukan dengan mode yang disediakan untuk aliran data Kinesis:
+ Rumus ini membantu memperkirakan jumlah pecahan yang akan diperlukan untuk mengakomodasi catatan data perubahan DynamoDB Anda. Ini tidak mewakili jumlah total pecahan yang dibutuhkan dalam aliran data Kinesis Anda, seperti jumlah pecahan yang diperlukan untuk mendukung konsumen aliran data Kinesis tambahan.
+ Anda mungkin masih mengalami pengecualian throughput baca dan tulis dalam mode yang disediakan jika Anda tidak mengonfigurasi aliran data untuk menangani throughput puncak Anda. Dalam hal ini, Anda harus menskalakan aliran data Anda secara manual untuk mengakomodasi lalu lintas data Anda. 
+ Rumus ini mempertimbangkan bloat tambahan yang dihasilkan oleh DynamoDB sebelum mengalirkan catatan data log perubahan ke Kinesis Data Stream.

Untuk mempelajari lebih lanjut tentang mode kapasitas pada Kinesis Data Stream lihat [Memilih Mode Kapasitas Aliran Data](https://docs.aws.amazon.com/streams/latest/dev/how-do-i-size-a-stream.html). Untuk mempelajari selengkapnya tentang perbedaan harga antara mode kapasitas yang berbeda, lihat harga [Amazon Kinesis Data Streams](https://aws.amazon.com/kinesis/data-streams/pricing/).

## Memantau pengambilan data perubahan dengan Kinesis Data Streams
<a name="kds_using-shards-and-metrics.monitoring"></a>

DynamoDB menyediakan beberapa metrik CloudWatch Amazon untuk membantu Anda memantau replikasi pengambilan data perubahan ke Kinesis. Untuk daftar lengkap CloudWatch metrik, lihat[Dimensi dan Metrik DynamoDB](metrics-dimensions.md).

Untuk menentukan apakah streaming Anda memiliki kapasitas yang memadai, sebaiknya pantau item berikut selama pengaktifan streaming dan produksi:
+ `ThrottledPutRecordCount`: Jumlah catatan yang dibatasi oleh aliran data Kinesis Anda karena kapasitas aliran data Kinesis tidak mencukupi. Anda mungkin mengalami beberapa throttling selama puncak penggunaan yang luar biasa, namun `ThrottledPutRecordCount` harus tetap serendah mungkin. DynamoDB mencoba lagi mengirimkan catatan yang dibatasi ke aliran data Kinesis, namun hal ini mungkin mengakibatkan latensi replikasi yang lebih tinggi. 

  Jika Anda mengalami throttling yang berlebihan dan secara rutin, maka Anda mungkin perlu meningkatkan jumlah serpihan aliran Kinesis secara proporsional dengan throughput tulis yang diamati pada tabel Anda. Untuk mempelajari selengkapnya tentang menentukan ukuran Kinesis data stream, lihat [Menentukan Ukuran Awal Kinesis Data Stream](https://docs.aws.amazon.com/streams/latest/dev/amazon-kinesis-streams.html#how-do-i-size-a-stream).
+ `AgeOfOldestUnreplicatedRecord`: Waktu yang berlalu sejak perubahan tingkat item terlama yang belum direplikasi ke aliran data Kinesis muncul di tabel DynamoDB. Dalam operasi normal, `AgeOfOldestUnreplicatedRecord` harus dalam urutan milidetik. Jumlah ini bertambah berdasarkan upaya replikasi yang gagal karena pilihan konfigurasi yang dikontrol pelanggan.

   Jika `AgeOfOldestUnreplicatedRecord` metrik melebihi 168 jam, replikasi perubahan tingkat item dari tabel DynamoDB ke aliran data Kinesis akan dinonaktifkan secara otomatis.

  Contoh konfigurasi yang dikontrol pelanggan yang menyebabkan upaya replikasi gagal adalah kapasitas aliran data Kinesis yang kurang tersedia sehingga menyebabkan throttling berlebihan, atau pembaruan manual pada kebijakan akses aliran data Kinesis Anda yang mencegah DynamoDB menambahkan data ke aliran data Anda. Untuk menjaga metrik ini serendah mungkin, Anda mungkin perlu memastikan penyediaan kapasitas aliran data Kinesis yang tepat, dan memastikan bahwa izin DynamoDB tidak berubah. 
+ `FailedToReplicateRecordCount`: Jumlah catatan yang gagal direplikasi DynamoDB ke Kinesis data stream Anda. Item tertentu yang lebih besar dari 34 KB mungkin bertambah besar ukurannya untuk mengubah catatan data yang lebih besar dari batas ukuran item 1 MB Kinesis Data Streams. Perluasan ukuran ini terjadi ketika item yang lebih besar dari 34 KB ini menyertakan sejumlah besar nilai atribut Boolean atau kosong. Nilai atribut Boolean dan kosong disimpan sebagai 1 byte di DynamoDB, namun diperluas hingga 5 byte saat diserialkan menggunakan JSON standar untuk replikasi Kinesis Data Streams. DynamoDB tidak dapat mereplikasi catatan perubahan tersebut ke aliran data Kinesis Anda. DynamoDB akan melewatkan catatan data perubahan ini, dan secara otomatis akan tetap melakukan replikasi atas catatan-catatan berikutnya. 

   

Anda dapat membuat CloudWatch alarm Amazon yang mengirim pesan Amazon Simple Notification Service (Amazon SNS) untuk pemberitahuan ketika salah satu metrik sebelumnya melebihi ambang batas tertentu. 

# Menggunakan kebijakan IAM untuk Amazon Kinesis Data Streams dan Amazon DynamoDB
<a name="kds_iam"></a>

Saat pertama kali Anda mengaktifkan Amazon Kinesis Data Streams untuk Amazon DynamoDB, DynamoDB secara otomatis membuat peran terkait layanan (IAM) untuk Anda. AWS Identity and Access Management Peran ini, `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication`, memungkinkan DynamoDB untuk mengelola replikasi perubahan tingkat item ke Kinesis Data Streams atas nama Anda. Jangan hapus peran tertaut layanan ini.

Untuk informasi selengkapnya tentang peran tertaut layanan, lihat [Menggunakan peran tertaut layanan](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html) di *Panduan Pengguna IAM*.

**catatan**  
DynamoDB tidak mendukung kondisi berbasis tag untuk kebijakan IAM.

Untuk mengaktifkan Amazon Kinesis Data Streams untuk Amazon DynamoDB, Anda harus memiliki izin berikut di tabel:
+ `dynamodb:EnableKinesisStreamingDestination`
+ `kinesis:ListStreams`
+ `kinesis:PutRecords`
+ `kinesis:DescribeStream`

Untuk menjelaskan Amazon Kinesis Data Streams untuk Amazon DynamoDB untuk tabel DynamoDB tertentu, Anda harus memiliki izin berikut pada tabel.
+ `dynamodb:DescribeKinesisStreamingDestination`
+ `kinesis:DescribeStreamSummary`
+ `kinesis:DescribeStream`

Untuk menonaktifkan Amazon Kinesis Data Streams untuk Amazon DynamoDB, Anda harus memiliki izin berikut pada tabel.
+ `dynamodb:DisableKinesisStreamingDestination`

Untuk memperbarui Amazon Kinesis Data Streams untuk Amazon DynamoDB, Anda harus memiliki izin berikut di atas tabel.
+ `dynamodb:UpdateKinesisStreamingDestination`

Contoh berikut menunjukkan cara menggunakan kebijakan IAM untuk memberikan izin untuk Amazon Kinesis Data Streams untuk Amazon DynamoDB.

## Contoh: Mengaktifkan Amazon Kinesis Data Streams untuk Amazon DynamoDB
<a name="access-policy-kds-example1"></a>

Kebijakan IAM berikut memberikan izin untuk mengaktifkan Amazon Kinesis Data Streams untuk Amazon DynamoDB untuk tabel. `Music` Itu tidak memberikan izin untuk menonaktifkan, memperbarui atau menjelaskan Kinesis Data Streams untuk DynamoDB untuk tabel. `Music` 

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "iam:CreateServiceLinkedRole",
            "Resource": "arn:aws:iam::*:role/aws-service-role/kinesisreplication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBKinesisDataStreamsReplication",
            "Condition": {
                "StringLike": {
                    "iam:AWSServiceName": "kinesisreplication.dynamodb.amazonaws.com"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:EnableKinesisStreamingDestination"
            ],
            "Resource": "arn:aws:dynamodb:us-west-2:111122223333:table/Music"
        }
    ]
}
```

------

## Contoh: Perbarui Amazon Kinesis Data Streams untuk Amazon DynamoDB
<a name="access-policy-kds-example2"></a>

Kebijakan IAM berikut memberikan izin untuk memperbarui Amazon Kinesis Data Streams untuk Amazon DynamoDB untuk tabel. `Music` Itu tidak memberikan izin untuk mengaktifkan, menonaktifkan, atau menjelaskan Amazon Kinesis Data Streams untuk Amazon DynamoDB untuk tabel. `Music` 

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:UpdateKinesisStreamingDestination"
            ],
            "Resource": "arn:aws:dynamodb:us-west-2:111122223333:table/Music"
        }
    ]
}
```

------

## Contoh: Menonaktifkan Amazon Kinesis Data Streams untuk Amazon DynamoDB
<a name="access-policy-kds-example2"></a>

Kebijakan IAM berikut memberikan izin untuk menonaktifkan Amazon Kinesis Data Streams untuk Amazon DynamoDB untuk tabel. `Music` Itu tidak memberikan izin untuk mengaktifkan, memperbarui, atau menjelaskan Amazon Kinesis Data Streams untuk Amazon DynamoDB untuk tabel. `Music` 

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:DisableKinesisStreamingDestination"
            ],
            "Resource": "arn:aws:dynamodb:us-west-2:111122223333:table/Music"
        }
    ]
}
```

------

## Contoh: Selektif menerapkan izin untuk Amazon Kinesis Data Streams untuk Amazon DynamoDB berdasarkan sumber daya
<a name="access-policy-kds-example3"></a>

Kebijakan IAM berikut memberikan izin untuk mengaktifkan dan menjelaskan Amazon Kinesis Data Streams untuk Amazon DynamoDB untuk tabel, dan menolak izin untuk menonaktifkan Amazon Kinesis Data Streams `Music` untuk Amazon DynamoDB untuk tabel. `Orders` 

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:EnableKinesisStreamingDestination",
                "dynamodb:DescribeKinesisStreamingDestination"
            ],
            "Resource": "arn:aws:dynamodb:us-west-2:111122223333:table/Music"
        },
        {
            "Effect": "Deny",
            "Action": [
                "dynamodb:DisableKinesisStreamingDestination"
            ],
            "Resource": "arn:aws:dynamodb:us-west-2:111122223333:table/Orders"
        }
    ]
}
```

------

## Menggunakan peran tertaut layanan untuk Kinesis Data Streams untuk DynamoDB
<a name="kds-service-linked-roles"></a>

[Amazon Kinesis Data Streams untuk Amazon DynamoDB menggunakan peran terkait layanan ( AWS Identity and Access Management IAM).](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-service-linked-role) Peran tertaut layanan adalah jenis IAM role unik yang ditautkan langsung ke Kinesis Data Streams untuk DynamoDB. Peran terkait layanan telah ditentukan sebelumnya oleh Kinesis Data Streams untuk DynamoDB dan menyertakan semua izin yang diperlukan layanan untuk memanggil layanan lain atas nama Anda. AWS 

Peran tertaut layanan membuat pengaturan Kinesis Data Streams untuk DynamoDB lebih mudah karena Anda tidak perlu menambahkan izin yang diperlukan secara manual. Kinesis Data Streams untuk DynamoDB menentukan izin peran terkait layanannya, dan kecuali ditentukan lain, hanya Kinesis Data Streams untuk DynamoDB yang dapat mengambil peran tersebut. Izin yang ditentukan mencakup kebijakan kepercayaan dan kebijakan izin, serta bahwa kebijakan izin tidak dapat dilampirkan ke entitas IAM lainnya.

Untuk informasi tentang layanan lain yang mendukung peran terkait layanan, lihat [Layanan AWS yang Berfungsi dengan IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html) dan cari layanan yang memiliki **Ya** di kolom **Peran Terkait Layanan**. Pilih **Ya** dengan tautan untuk melihat dokumentasi peran terkait layanan untuk layanan tersebut.

### Izin peran tertaut layanan untuk Kinesis Data Streams untuk DynamoDB
<a name="slr-permissions"></a>

Kinesis Data Streams untuk DynamoDB menggunakan peran terkait layanan bernama. **AWSServiceRoleForDynamoDBKinesisDataStreamsReplication** Tujuan dari peran tertaut layanan adalah untuk memungkinkan Amazon DynamoDB mengelola replikasi perubahan tingkat item pada Kinesis Data Streams, atas nama Anda.

Peran tertaut layanan `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication` memercayai layanan berikut untuk mengambil peran tersebut:
+ `kinesisreplication.dynamodb.amazonaws.com`

Kebijakan izin peran memungkinkan Kinesis Data Streams for DynamoDB menyelesaikan tindakan berikut pada sumber daya yang ditentukan:
+ Tindakan: `Put records and describe` pada `Kinesis stream`
+ Tindakan: `Generate data keys` aktif `AWS KMS` untuk menempatkan data pada aliran Kinesis yang dienkripsi menggunakan kunci Buatan Pengguna. AWS KMS 

Untuk isi dokumen kebijakan yang tepat, lihat [Dynamo DBKinesis ReplicationServiceRolePolicy](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/aws-service-role/DynamoDBKinesisReplicationServiceRolePolicy).

Anda harus mengonfigurasi izin untuk mengizinkan entitas IAM (seperti pengguna, grup, atau peran) untuk membuat, mengedit, atau menghapus peran terkait layanan. Untuk informasi selengkapnya, silakan lihat [Izin Peran Tertaut Layanan](https://docs.aws.amazon.com/IAM/latest/UserGuide/contributorinsights-service-linked-roles.html#service-linked-role-permissions) di *Panduan Pengguna IAM*.

### Membuat peran tertaut layanan untuk Kinesis Data Streams untuk DynamoDB
<a name="create-slr"></a>

Anda tidak perlu membuat peran terkait layanan secara manual. Saat Anda mengaktifkan Kinesis Data Streams untuk Konsol Manajemen AWS DynamoDB di AWS CLI, atau AWS API, Kinesis Data Streams untuk DynamoDB akan membuat peran terkait layanan untuk Anda. 

Jika Anda menghapus peran terkait layanan ini, dan ingin membuatnya lagi, Anda dapat mengulangi proses yang sama untuk membuat kembali peran tersebut di akun Anda. Saat Anda mengaktifkan Kinesis Data Streams untuk DynamoDB, Kinesis Data Streams untuk DynamoDB menciptakan peran terkait layanan untuk Anda lagi. 

### Mengedit peran tertaut layanan untuk Kinesis Data Streams untuk DynamoDB
<a name="edit-slr"></a>

Kinesis Data Streams untuk DynamoDB tidak mengizinkan Anda mengedit peran tertaut layanan `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication`. Setelah membuat peran terkait layanan, Anda tidak dapat mengubah nama peran karena berbagai entitas mungkin mereferensikan peran tersebut. Namun, Anda dapat mengedit penjelasan peran menggunakan IAM. Untuk informasi selengkapnya, lihat [Mengedit Peran terkait Layanan](https://docs.aws.amazon.com/IAM/latest/UserGuide/contributorinsights-service-linked-roles.html#edit-service-linked-role) di *Panduan Pengguna IAM*.

### Menghapus peran tertaut layanan untuk Kinesis Data Streams untuk DynamoDB
<a name="delete-slr"></a>

Anda juga dapat menggunakan konsol IAM, AWS CLI atau AWS API untuk menghapus peran terkait layanan secara manual. Untuk melakukannya, Anda harus membersihkan sumber daya untuk peran tertaut layanan terlebih dahulu, lalu Anda dapat menghapusnya secara manual.

**catatan**  
Jika layanan Kinesis Data Streams for DynamoDB menggunakan peran tersebut saat Anda mencoba menghapus sumber daya, maka penghapusan mungkin gagal. Jika hal itu terjadi, tunggu beberapa menit dan coba lagi.

**Untuk menghapus peran tertaut layanan secara manual menggunakan IAM**

Gunakan konsol IAM, the AWS CLI, atau AWS API untuk menghapus peran `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication` terkait layanan. Untuk informasi selengkapnya, lihat [Menghapus Peran Terkait Layanan](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html) di *Panduan Pengguna IAM*.

# Tangkapan data perubahan DynamoDB Streams
<a name="Streams"></a>

 DynamoDB Streams menangkap urutan waktu modifikasi tingkat item di tabel DynamoDB mana pun dan menyimpan informasi ini dalam log hingga 24 jam. Aplikasi dapat mengakses log ini dan melihat item data seperti yang muncul sebelum dan setelah diubah, hampir secara waktu nyata.

 Enkripsi saat istirahat mengenkripsi data dalam DynamoDB streams. Untuk informasi selengkapnya, lihat [Enkripsi DynamoDB saat diam](EncryptionAtRest.md).

*Streami DynamoDB* adalah aliran berurutan informasi tentang perubahan item dalam tabel DynamoDB. Saat Anda mengaktifkan aliran pada tabel, DynamoDB menangkap informasi tentang setiap modifikasi pada item data dalam tabel.

Setiap kali aplikasi membuat, memperbarui, atau menghapus item dalam tabel, DynamoDB Streams menulis rekaman aliran dengan atribut kunci primer dari item yang diubah. *Catatan stream* berisi informasi tentang modifikasi data pada satu item dalam tabel DynamoDB. Anda dapat mengonfigurasi aliran sehingga rekaman aliran menangkap informasi tambahan, seperti gambar "sebelum" dan "sesudah" dari item yang diubah.

DynamoDB Streams membantu memastikan hal berikut:
+ Setiap catatan stream muncul tepat sekali dalam stream.
+ Untuk setiap item yang diubah dalam tabel DynamoDB, catatan stream muncul dalam urutan yang sama seperti modifikasi aktual untuk item.

DynamoDB Streams menulis catatan aliran hampir secara real-time sehingga Anda dapat membangun aplikasi yang menggunakan aliran ini dan mengambil tindakan berdasarkan kontennya.

**Topics**
+ [Titik akhir untuk DynamoDB Streams](#Streams.Endpoints)
+ [Mengaktifkan aliran](#Streams.Enabling)
+ [Membaca dan memproses aliran](#Streams.Processing)
+ [DynamoDB Streams dan Waktu untuk Tayang](time-to-live-ttl-streams.md)
+ [Menggunakan adaptor DynamoDB Streams Kinesis untuk memproses catatan aliran](Streams.KCLAdapter.md)
+ [API tingkat rendah DynamoDB Streams: Contoh Java](Streams.LowLevel.Walkthrough.md)
+ [DynamoDB Streams dan pemicu AWS Lambda](Streams.Lambda.md)
+ [DynamoDB Streams dan Apache Flink](StreamsApacheFlink.xml.md)

## Titik akhir untuk DynamoDB Streams
<a name="Streams.Endpoints"></a>

AWS mempertahankan endpoint terpisah untuk DynamoDB dan DynamoDB Streams. Untuk bekerja dengan tabel dan indeks basis data, aplikasi Anda harus mengakses titik akhir DynamoDB. Untuk membaca dan memproses catatan DynamoDB Streams, aplikasi Anda harus mengakses titik akhir DynamoDB Streams di Wilayah yang sama.

DynamoDB Streams menawarkan dua set endpoint. File tersebut adalah:
+ **IPv4-only endpoint: Titik** akhir dengan konvensi `streams.dynamodb.<region>.amazonaws.com` penamaan.
+ **Dual-stack endpoint**: Endpoint baru yang kompatibel dengan keduanya IPv4 dan IPv6 dan mengikuti konvensi penamaan. `streams-dynamodb.<region>.api.aws`

**catatan**  
Untuk daftar lengkap Wilayah dan titik akhir DynamoDB dan DynamoDB Streams, lihat [Wilayah dan titik akhir](https://docs.aws.amazon.com/general/latest/gr/rande.html) di *Referensi Umum AWS*.

 AWS SDKs Menyediakan klien terpisah untuk DynamoDB dan DynamoDB Streams. Bergantung pada kebutuhan Anda, aplikasi Anda dapat mengakses titik akhir DynamoDB, titik akhir DynamoDB Streams, atau keduanya secara bersamaan. Untuk terhubung ke kedua titik akhir, aplikasi Anda harus membuat instance dua klien—satu untuk DynamoDB dan satu lagi untuk DynamoDB Streams.

## Mengaktifkan aliran
<a name="Streams.Enabling"></a>

Anda dapat mengaktifkan aliran pada tabel baru saat Anda membuatnya menggunakan AWS CLI atau salah satu tabel AWS SDKs. Anda juga dapat mengaktifkan atau menonaktifkan aliran pada tabel yang sudah ada, atau mengubah pengaturan aliran. DynamoDB Streams beroperasi secara asinkron, sehingga tidak ada dampak kinerja pada tabel jika Anda mengaktifkan aliran.

Cara termudah untuk mengelola DynamoDB Streams adalah dengan menggunakan Konsol Manajemen AWS.

1. Masuk ke Konsol Manajemen AWS dan buka konsol DynamoDB di. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Pada dasbor konsol DynamoDB, pilih **Tabel** dan pilih tabel yang ada.

1. Pilih tab **Ekspor dan aliran**.

1. **Di bagian detail **aliran DynamoDB**, pilih Aktifkan.**

1. Pada halaman Aliran **DynamoDB**, pilih informasi yang akan ditulis ke aliran setiap kali data dalam tabel diubah:
   + **Atribut kunci saja** — Hanya atribut kunci dari item yang dimodifikasi.
   + **Gambar baru** — Seluruh item, saat muncul setelah diubah.
   + **Gambar lama** — Seluruh item, saat muncul sebelum diubah.
   + **Gambar baru dan lama** — Baik gambar baru dan lama dari item.

   Ketika pengaturan seperti yang Anda inginkan, pilih **Aktifkan aliran**.

1. (Opsional) Untuk menonaktifkan aliran yang ada, pilih **Matikan di bawah detail** aliran **DynamoDB**.

Anda juga dapat menggunakan operasi `CreateTable` atau `UpdateTable` API untuk mengaktifkan atau memodifikasi aliran. Parameter `StreamSpecification` menentukan bagaimana aliran dikonfigurasi:
+ `StreamEnabled` — Menentukan apakah stream diaktifkan (`true`) atau dinonaktifkan (`false`) untuk tabel.
+ `StreamViewType` — Menentukan informasi yang akan ditulis ke stream setiap kali data dalam tabel dimodifikasi:
  + `KEYS_ONLY` — Hanya atribut kunci dari item yang dimodifikasi.
  + `NEW_IMAGE` — Keseluruhan item, seperti yang muncul setelah diubah.
  + `OLD_IMAGE` — Keseluruhan item, seperti yang terlihat sebelum diubah.
  + `NEW_AND_OLD_IMAGES` — Baik gambar baru dan lama dari item.

Anda dapat mengaktifkan atau menonaktifkan stream kapan saja. Namun, Anda menerima `ValidationException` jika Anda mencoba untuk mengaktifkan stream pada tabel yang sudah memiliki stream. Anda juga menerima `ValidationException` jika Anda mencoba menonaktifkan aliran pada tabel yang tidak memiliki aliran.

Ketika Anda mengatur `StreamEnabled` ke `true`, DynamoDB menciptakan stream baru dengan deskriptor stream unik yang ditugaskan untuk itu. Jika Anda menonaktifkan dan kemudian mengaktifkan kembali stream pada tabel, stream baru dibuat dengan deskriptor stream yang berbeda.

Setiap stream diidentifikasi secara unik oleh Amazon Resource Name (ARN). Berikut ini adalah contoh ARN untuk stream pada tabel DynamoDB bernama `TestTable`.

```
arn:aws:dynamodb:us-west-2:111122223333:table/TestTable/stream/2015-05-11T21:21:33.291
```

Untuk menentukan deskriptor stream terbaru untuk tabel, terbitkan permintaan `DescribeTable` DynamoDB dan cari elemen `LatestStreamArn` dalam respons.

**catatan**  
Hal ini tidak mungkin untuk mengedit `StreamViewType` setelah stream telah diatur. Jika Anda perlu melakukan perubahan pada stream setelah pengaturan, Anda harus menonaktifkan stream saat ini dan membuat yang baru.

## Membaca dan memproses aliran
<a name="Streams.Processing"></a>

Untuk membaca dan memproses aliran, aplikasi Anda harus terhubung ke titik akhir DynamoDB Streams dan menerbitkan permintaan API.

Stream terdiri dari *catatan aliran*. Setiap catatan stream mewakili modifikasi data tunggal dalam tabel DynamoDB di mana aliran berada. Setiap catatan stream ditugaskan nomor urut, mencerminkan urutan catatan diterbitkan ke aliran.

Rekaman streaming disusun ke dalam grup, atau *serpihan*. Setiap serpihan bertindak sebagai kontainer untuk beberapa catatan aliran, dan berisi informasi yang diperlukan untuk mengakses dan iterasi melalui catatan-catatan ini. Catatan stream dalam serpihan dihapus secara otomatis setelah 24 jam.

Serpihan bersifat fana: Mereka dibuat dan dihapus secara otomatis, sesuai kebutuhan. Setiap serpihan juga dapat dibagi menjadi beberapa serpihan baru; ini juga terjadi secara otomatis. (Pecahan induk juga mungkin hanya memiliki satu pecahan turunan.) Sebuah pecahan mungkin terpecah sebagai respons terhadap aktivitas tulis tingkat tinggi pada tabel induknya, sehingga aplikasi dapat memproses rekaman dari beberapa pecahan secara paralel.

Jika Anda menonaktifkan aliran, semua pecahan yang terbuka akan ditutup. Data dalam aliran akan terus dapat dibaca selama 24 jam.

Karena serpihan memiliki garis keturunan (induk dan turunan), aplikasi harus selalu memproses serpihan induk sebelum memproses serpihan anak. Hal ini membantu memastikan bahwa rekaman aliran juga diproses dalam urutan yang benar. (Jika Anda menggunakan DynamoDB Streams Kinesis Adapter, hal ini akan ditangani untuk Anda. Aplikasi Anda memproses pecahan dan catatan aliran dalam urutan yang benar. Secara otomatis menangani pecahan baru atau yang sudah habis masa berlakunya, selain pecahan yang terpecah saat aplikasi berjalan. Misalnya informasi lebih lanjut, lihat [Menggunakan adaptor DynamoDB Streams Kinesis untuk memproses catatan aliran](Streams.KCLAdapter.md).)

Diagram berikut menunjukkan hubungan antara aliran, serpihan dalam aliran, dan rekaman aliran dalam serpihan.

![\[Struktur DynamoDB Streams. Catatan aliran yang mewakili modifikasi data diatur ke dalam pecahan.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/streams-terminology.png)


**catatan**  
Jika Anda melakukan operasi `PutItem` atau `UpdateItem` yang tidak mengubah data dalam item, DynamoDB Streams *tidak* menulis catatan stream untuk operasi itu.

Untuk mengakses aliran dan memproses rekaman aliran di dalamnya, Anda harus melakukan hal berikut:
+ Tentukan ARN unik aliran yang ingin Anda akses.
+ Tentukan pecahan mana dalam aliran yang berisi rekaman aliran yang Anda minati.
+ Akses pecahan dan ambil rekaman aliran yang Anda inginkan.

**catatan**  
Maksimum dua proses harus membaca dari pecahan aliran yang sama pada waktu yang sama. Memiliki lebih dari dua pembaca per shard dapat mengakibatkan throttling.

DynamoDB Streams API menyediakan tindakan berikut untuk digunakan oleh program aplikasi:
+  `[ListStreams](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_ListStreams.html)` — Mengembalikan daftar deskriptor stream untuk akun dan titik akhir saat ini. Anda secara opsional dapat meminta hanya deskriptor stream untuk nama tabel tertentu.
+ `[DescribeStream](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_DescribeStream.html)`— Mengembalikan informasi tentang aliran, termasuk status aliran saat ini, Nama Sumber Daya Amazon (ARN), komposisi pecahannya, dan tabel DynamoDB yang sesuai. Anda dapat menggunakan `ShardFilter` bidang ini secara opsional untuk mengambil pecahan anak yang ada yang terkait dengan pecahan induk.
+ `[GetShardIterator](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_GetShardIterator.html)` — Mengembalikan *iterator serpihan*, yang menggambarkan lokasi di dalam serpihan. Anda dapat meminta iterator yang menyediakan akses ke titik terlama, titik terbaru, atau titik tertentu dalam serpihan.
+ `[GetRecords](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_GetRecords.html)` - Mengembalikan catatan aliran dari dalam serpihan yang diberikan. Anda harus memberikan iterator serpihan yang dikembalikan dari permintaan `GetShardIterator`.

Untuk deskripsi lengkap operasi API ini, termasuk contoh permintaan dan tanggapan, lihat [Referensi API Amazon DynamoDB Streams](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Operations_Amazon_DynamoDB_Streams.html).

### Penemuan pecahan
<a name="Streams.ShardDiscovery"></a>



Temukan pecahan baru di aliran DynamoDB Anda dengan dua metode canggih. Sebagai pengguna Amazon DynamoDB Streams, Anda memiliki dua cara efektif untuk melacak dan mengidentifikasi pecahan baru:

**Polling seluruh topologi aliran**  
Gunakan `DescribeStream` API untuk melakukan polling streaming secara teratur. Ini mengembalikan semua pecahan dalam aliran, termasuk pecahan baru yang telah dibuat. Dengan membandingkan hasil dari waktu ke waktu, Anda dapat mendeteksi pecahan yang baru ditambahkan.

**Menemukan pecahan anak**  
Gunakan `DescribeStream` API dengan `ShardFilter` parameter untuk menemukan subset pecahan. Dengan menentukan pecahan induk dalam permintaan, DynamoDB Streams akan mengembalikan pecahan turunan langsungnya. Pendekatan ini berguna ketika Anda hanya perlu melacak garis keturunan pecahan tanpa memindai seluruh aliran.   
Aplikasi yang mengkonsumsi data dari DynamoDB Streams dapat secara efisien bertransisi dari membaca pecahan tertutup ke pecahan turunannya menggunakan parameter `ShardFilter` ini, menghindari panggilan berulang ke API untuk mengambil dan melintasi `DescribeStream` peta pecahan untuk semua pecahan tertutup dan terbuka. Ini membantu menemukan pecahan anak dengan cepat setelah pecahan induk ditutup, membuat aplikasi pemrosesan aliran Anda lebih responsif dan hemat biaya.

Kedua metode memberdayakan Anda untuk tetap berada di atas struktur DynamoDB Streams yang berkembang, memastikan Anda tidak pernah melewatkan pembaruan data penting atau modifikasi pecahan.

### Batas retensi data untuk DynamoDB Streams
<a name="Streams.DataRetention"></a>

Semua data dalam DynamoDB Streams tunduk pada masa hidup 24 jam. Anda dapat mengambil dan menganalisis 24 jam terakhir aktivitas untuk setiap tabel yang ditentukan. Namun, data yang lebih lama dari 24 jam rentan terhadap pemangkasan (penghapusan) setiap saat.

Jika Anda menonaktifkan stream pada tabel, data di stream terus dapat dibaca selama 24 jam. Setelah waktu ini, data kedaluwarsa dan catatan stream secara otomatis dihapus. Tidak ada mekanisme untuk menghapus stream yang ada secara manual. Anda harus menunggu hingga batas retensi berakhir (24 jam), dan semua catatan stream akan dihapus.

# DynamoDB Streams dan Waktu untuk Tayang
<a name="time-to-live-ttl-streams"></a>

Anda dapat mencadangkan, atau memproses, item yang dihapus oleh [Waktu untuk Tayang](TTL.md) (TTL) dengan mengaktifkan Amazon DynamoDB Stream pada tabel dan memproses catatan stream dari item yang kedaluwarsa. Untuk informasi selengkapnya, lihat [Membaca dan memproses aliran](Streams.md#Streams.Processing).

Catatan stream berisi bidang identitas pengguna `Records[<index>].userIdentity`.

Item yang dihapus oleh proses Waktu untuk Tayang setelah kedaluwarsa memiliki bidang berikut:
+ `Records[<index>].userIdentity.type`

  `"Service"`
+ `Records[<index>].userIdentity.principalId`

  `"dynamodb.amazonaws.com"`

**catatan**  
Saat Anda menggunakan TTL dalam tabel global, wilayah tempat TTL dilakukan akan memiliki `userIdentity` bidang yang ditetapkan. Bidang ini tidak akan disetel di wilayah lain saat penghapusan direplikasi.

JSON berikut menunjukkan bagian yang relevan dari catatan stream tunggal.

```
"Records": [
    {
        ...

        "userIdentity": {
            "type": "Service",
            "principalId": "dynamodb.amazonaws.com"
        }

        ...

    }
]
```

## Menggunakan DynamoDB Streams dan Lambda untuk mengarsipkan item TTL yang dihapus
<a name="streams-archive-ttl-deleted-items"></a>

Menggabungkan [Waktu untuk Tayang (TTL) DynamoDB, DynamoDB Streams,](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html) dan [AWS Lambda](https://aws.amazon.com/lambda/) dapat membantu menyederhanakan pengarsipan [data, mengurangi biaya penyimpanan DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html), dan mengurangi kompleksitas kode. Menggunakan Lambda sebagai konsumen aliran memberikan banyak keuntungan, terutama pengurangan biaya dibandingkan dengan konsumen lain seperti Kinesis Client Library (KCL). Anda tidak dikenakan biaya untuk panggilan API `GetRecords` di aliran DynamoDB saat menggunakan Lambda untuk mengkonsumsi peristiwa, dan Lambda dapat menyediakan pemfilteran peristiwa dengan mengidentifikasi pola JSON dalam peristiwa streaming. Dengan pemfilteran konten pola peristiwa, Anda dapat menentukan hingga lima filter berbeda untuk mengontrol peristiwa mana yang dikirim ke Lambda untuk diproses. Hal ini membantu mengurangi pemanggilan fungsi Lambda Anda, menyederhanakan kode, dan mengurangi biaya keseluruhan.

Meskipun DynamoDB Streams berisi semua modifikasi data, seperti tindakan `Create`, `Modify`, dan `Remove`, hal ini dapat mengakibatkan pemanggilan yang tidak diinginkan pada fungsi Lambda arsip Anda. Misalnya, Anda memiliki tabel dengan 2 juta modifikasi data per jam yang mengalir ke aliran, namun kurang dari 5 persen di antaranya adalah penghapusan item yang akan kedaluwarsa melalui proses TTL dan perlu diarsipkan. Dengan [filter sumber acara Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html), fungsi Lambda hanya akan dipanggil 100.000 kali per jam. Hasil dari pemfilteran peristiwa adalah Anda hanya dikenakan biaya untuk pemanggilan yang diperlukan, bukan 2 juta pemanggilan yang akan Anda dapatkan tanpa pemfilteran peristiwa.

Pemfilteran peristiwa diterapkan pada [pemetaan sumber peristiwa Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventsourcemapping.html), yang merupakan sumber daya yang membaca dari peristiwa yang dipilih—aliran DynamoDB—dan memanggil fungsi Lambda. Dalam diagram berikut, Anda dapat melihat bagaimana item Time to Live yang dihapus digunakan oleh fungsi Lambda menggunakan aliran dan filter peristiwa.

![\[Item yang dihapus melalui proses TTL memulai fungsi Lambda yang menggunakan aliran dan filter acara.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/streams-lambda-ttl.png)


### Pola filter peristiwa DynamoDB Waktu untuk Tayang
<a name="ttl-event-filter-pattern"></a>

Menambahkan JSON berikut ke [kriteria filter](https://docs.aws.amazon.com/lambda/latest/dg/API_FilterCriteria.html) pemetaan sumber peristiwa Anda memungkinkan invokasi fungsi Lambda Anda hanya untuk item yang dihapus TTL:

```
{
    "Filters": [
        {
            "Pattern": { "userIdentity": { "type": ["Service"], "principalId": ["dynamodb.amazonaws.com"] } }
        }
    ]
}
```

### Membuat pemetaan sumber AWS Lambda acara
<a name="create-event-source-mapping"></a>

Gunakan cuplikan kode berikut untuk membuat pemetaan sumber peristiwa terfilter yang dapat Anda sambungkan ke aliran DynamoDB tabel. Setiap blok kode menyertakan pola filter peristiwa.

------
#### [ AWS CLI ]

```
aws lambda create-event-source-mapping \
--event-source-arn 'arn:aws:dynamodb:eu-west-1:012345678910:table/test/stream/2021-12-10T00:00:00.000' \
--batch-size 10 \
--enabled \
--function-name test_func \
--starting-position LATEST \
--filter-criteria '{"Filters": [{"Pattern": "{\"userIdentity\":{\"type\":[\"Service\"],\"principalId\":[\"dynamodb.amazonaws.com\"]}}"}]}'
```

------
#### [ Java ]

```
LambdaClient client = LambdaClient.builder()
        .region(Region.EU_WEST_1)
        .build();

Filter userIdentity = Filter.builder()
        .pattern("{\"userIdentity\":{\"type\":[\"Service\"],\"principalId\":[\"dynamodb.amazonaws.com\"]}}")
        .build();

FilterCriteria filterCriteria = FilterCriteria.builder()
        .filters(userIdentity)
        .build();

CreateEventSourceMappingRequest mappingRequest = CreateEventSourceMappingRequest.builder()
        .eventSourceArn("arn:aws:dynamodb:eu-west-1:012345678910:table/test/stream/2021-12-10T00:00:00.000")
        .batchSize(10)
        .enabled(Boolean.TRUE)
        .functionName("test_func")
        .startingPosition("LATEST")
        .filterCriteria(filterCriteria)
        .build();

try{
    CreateEventSourceMappingResponse eventSourceMappingResponse = client.createEventSourceMapping(mappingRequest);
    System.out.println("The mapping ARN is "+eventSourceMappingResponse.eventSourceArn());

}catch (ServiceException e){
    System.out.println(e.getMessage());
}
```

------
#### [ Node ]

```
const client = new LambdaClient({ region: "eu-west-1" });

const input = {
    EventSourceArn: "arn:aws:dynamodb:eu-west-1:012345678910:table/test/stream/2021-12-10T00:00:00.000",
    BatchSize: 10,
    Enabled: true,
    FunctionName: "test_func",
    StartingPosition: "LATEST",
    FilterCriteria: { "Filters": [{ "Pattern": "{\"userIdentity\":{\"type\":[\"Service\"],\"principalId\":[\"dynamodb.amazonaws.com\"]}}" }] }
}

const command = new CreateEventSourceMappingCommand(input);

try {
    const results = await client.send(command);
    console.log(results);
} catch (err) {
    console.error(err);
}
```

------
#### [ Python ]

```
session = boto3.session.Session(region_name = 'eu-west-1')
client = session.client('lambda')

try:
    response = client.create_event_source_mapping(
        EventSourceArn='arn:aws:dynamodb:eu-west-1:012345678910:table/test/stream/2021-12-10T00:00:00.000',
        BatchSize=10,
        Enabled=True,
        FunctionName='test_func',
        StartingPosition='LATEST',
        FilterCriteria={
            'Filters': [
                {
                    'Pattern': "{\"userIdentity\":{\"type\":[\"Service\"],\"principalId\":[\"dynamodb.amazonaws.com\"]}}"
                },
            ]
        }
    )
    print(response)
except Exception as e:
    print(e)
```

------
#### [ JSON ]

```
{
  "userIdentity": {
     "type": ["Service"],
     "principalId": ["dynamodb.amazonaws.com"]
   }
}
```

------

# Menggunakan adaptor DynamoDB Streams Kinesis untuk memproses catatan aliran
<a name="Streams.KCLAdapter"></a>

Menggunakan Adaptor Amazon Kinesis adalah cara yang disarankan untuk menggunakan aliran dari Amazon DynamoDB. DynamoDB Streams API sengaja mirip dengan Kinesis Data Streams. Di kedua layanan, aliran data terdiri dari pecahan, yang merupakan wadah untuk rekaman aliran. Kedua layanan APIs berisi`ListStreams`,, `DescribeStream``GetShards`, dan `GetShardIterator` operasi. (Meskipun tindakan DynamoDB Streams ini serupa dengan tindakan serupa di Kinesis Data Streams, tindakan tersebut tidak 100 persen identik.)

Sebagai pengguna DynamoDB Streams, Anda dapat menggunakan pola desain yang ditemukan dalam KCL untuk memproses serpihan dan rekaman aliran DynamoDB Streams. Untuk melakukan ini, Anda menggunakan Adaptor DynamoDB Streams Kinesis. Adaptor Kinesis mengimplementasikan antarmuka Kinesis Data Streams sehingga KCL dapat digunakan untuk menggunakan dan memproses catatan dari DynamoDB Streams. [Untuk petunjuk tentang cara mengatur dan menginstal Adaptor Kinesis DynamoDB Streams, lihat repositori. GitHub](https://github.com/awslabs/dynamodb-streams-kinesis-adapter)

Anda dapat menulis aplikasi untuk Kinesis Data Streams menggunakan Kinesis Client Library (KCL). KCL menyederhanakan pengodean dengan menyediakan abstraksi yang berguna di atas Kinesis Data Streams API tingkat rendah. Untuk informasi selengkapnya tentang KCL, lihat [Mengembangkan konsumen menggunakan Kinesis client library](https://docs.aws.amazon.com/kinesis/latest/dev/developing-consumers-with-kcl.html) dalam *Panduan Developer Amazon Kinesis Data Streams*.

DynamoDB merekomendasikan penggunaan KCL versi 3.x dengan SDK AWS for Java v2.x. [Adaptor Kinesis DynamoDB Streams versi AWS 1.x saat ini dengan AWS SDK untuk Java SDK untuk v1.x akan terus didukung sepenuhnya sepanjang siklus hidupnya sebagaimana dimaksud selama periode transisi sesuai dengan kebijakan pemeliharaan dan Tools.AWS SDKs ](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html)

**catatan**  
Perpustakaan Klien Amazon Kinesis (KCL) versi 1.x dan 2.x sudah usang. KCL 1.x akan mencapai end-of-support pada 30 Januari 2026. Kami sangat menyarankan Anda memigrasikan aplikasi KCL Anda menggunakan versi 1.x ke versi KCL terbaru sebelum 30 Januari 2026. Untuk menemukan versi KCL terbaru, lihat halaman Perpustakaan [Klien Amazon Kinesis](https://github.com/awslabs/amazon-kinesis-client) di. GitHub Untuk informasi tentang versi KCL terbaru, lihat [Menggunakan Perpustakaan Klien Kinesis](https://docs.aws.amazon.com/streams/latest/dev/kcl.html). Untuk informasi tentang migrasi dari KCL 1.x ke KCL 3.x, lihat Migrasi dari KCL 1.x ke KCL 3.x.

Diagram berikut menunjukkan bagaimana perpustakaan ini berinteraksi satu sama lain.

![\[Interaksi antara DynamoDB Streams, Kinesis Data Streams, dan KCL untuk memproses rekaman DynamoDB Streams.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/streams-kinesis-adapter.png)


Dengan Adaptor Kinesis DynamoDB Streams, Anda dapat mulai mengembangkan antarmuka KCL, dengan panggilan API diarahkan secara mulus ke titik akhir DynamoDB Streams.

Saat aplikasi Anda dimulai, aplikasi akan memanggil KCL untuk membuat instance pekerja. Anda harus memberi pekerja informasi konfigurasi untuk aplikasi, seperti deskriptor aliran dan AWS kredensil, dan nama kelas prosesor rekaman yang Anda berikan. Saat menjalankan kode di pemroses rekaman, pekerja melakukan tugas-tugas berikut:
+ Menghubungkan ke aliran
+ Menghitung pecahan dalam aliran
+ Memeriksa dan menghitung pecahan anak dari pecahan induk tertutup di dalam aliran
+ Mengkoordinasikan asosiasi serpihan dengan pekerja lain (jika ada)
+ Membuat instance pemroses rekaman untuk setiap pecahan yang dikelolanya
+ Menarik catatan dari aliran
+ Menskalakan tingkat panggilan GetRecords API selama throughput tinggi (jika mode catch-up dikonfigurasi)
+ Mendorong rekaman ke pemroses rekaman yang sesuai
+ Catatan yang diproses di pos pemeriksaan
+ Menyeimbangkan asosiasi pekerja pecahan ketika jumlah instans pekerja berubah
+ Menyeimbangkan asosiasi pekerja pecahan saat pecahan dipisahkan

Adaptor KCL mendukung mode catch-up, fitur penyesuaian laju panggilan otomatis untuk menangani peningkatan throughput sementara. Ketika kelambatan pemrosesan aliran melebihi ambang batas yang dapat dikonfigurasi (default satu menit), mode catch-up menskalakan frekuensi panggilan GetRecords API dengan nilai yang dapat dikonfigurasi (default 3x) untuk mengambil catatan lebih cepat, lalu kembali normal setelah jeda turun. Ini berharga selama periode throughput tinggi di mana aktivitas penulisan DynamoDB dapat membanjiri konsumen menggunakan tingkat polling default. Mode catch-up dapat diaktifkan melalui parameter `catchupEnabled` konfigurasi (default false).

**catatan**  
Untuk deskripsi konsep KCL yang tercantum di sini, lihat [Mengembangkan konsumen menggunakan Kinesis client library](https://docs.aws.amazon.com/kinesis/latest/dev/developing-consumers-with-kcl.html) di *Panduan Pengembang Amazon Kinesis Data Streams*.  
Untuk informasi lebih lanjut tentang menggunakan stream dengan lihat AWS Lambda [DynamoDB Streams dan pemicu AWS Lambda](Streams.Lambda.md)

# Migrasi dari KCL 1.x ke KCL 3.x
<a name="streams-migrating-kcl"></a>

## Ikhtisar
<a name="migrating-kcl-overview"></a>

Panduan ini memberikan petunjuk untuk memigrasikan aplikasi konsumen Anda dari KCL 1.x ke KCL 3.x. Karena perbedaan arsitektur antara KCL 1.x dan KCL 3.x, migrasi memerlukan pembaruan beberapa komponen untuk memastikan kompatibilitas.

KCL 1.x menggunakan kelas dan antarmuka yang berbeda dibandingkan dengan KCL 3.x. Anda harus memigrasikan prosesor rekaman, pabrik prosesor rekaman, dan kelas pekerja ke format yang kompatibel dengan KCL 3.x terlebih dahulu, dan ikuti langkah-langkah migrasi untuk migrasi KCL 1.x ke KCL 3.x.

## Langkah migrasi
<a name="migration-steps"></a>

**Topics**
+ [Langkah 1: Migrasikan prosesor rekaman](#step1-record-processor)
+ [Langkah 2: Migrasikan pabrik prosesor rekaman](#step2-record-processor-factory)
+ [Langkah 3: Migrasikan pekerja](#step3-worker-migration)
+ [Langkah 4: Ikhtisar dan rekomendasi konfigurasi KCL 3.x](#step4-configuration-migration)
+ [Langkah 5: Migrasi dari KCL 2.x ke KCL 3.x](#step5-kcl2-to-kcl3)

### Langkah 1: Migrasikan prosesor rekaman
<a name="step1-record-processor"></a>

Contoh berikut menunjukkan prosesor rekaman diimplementasikan untuk adaptor KCL 1.x DynamoDB Streams Kinesis:

```
package com.amazonaws.kcl;

import com.amazonaws.services.kinesis.clientlibrary.exceptions.InvalidStateException;
import com.amazonaws.services.kinesis.clientlibrary.exceptions.ShutdownException;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.IRecordProcessorCheckpointer;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IShutdownNotificationAware;
import com.amazonaws.services.kinesis.clientlibrary.lib.worker.ShutdownReason;
import com.amazonaws.services.kinesis.clientlibrary.types.InitializationInput;
import com.amazonaws.services.kinesis.clientlibrary.types.ProcessRecordsInput;
import com.amazonaws.services.kinesis.clientlibrary.types.ShutdownInput;

public class StreamsRecordProcessor implements IRecordProcessor, IShutdownNotificationAware {
    @Override
    public void initialize(InitializationInput initializationInput) {
        //
        // Setup record processor
        //
    }

    @Override
    public void processRecords(ProcessRecordsInput processRecordsInput) {
        for (Record record : processRecordsInput.getRecords()) {
            String data = new String(record.getData().array(), Charset.forName("UTF-8"));
            System.out.println(data);
            if (record instanceof RecordAdapter) {
                // record processing and checkpointing logic
            }
        }
    }

    @Override
    public void shutdown(ShutdownInput shutdownInput) {
        if (shutdownInput.getShutdownReason() == ShutdownReason.TERMINATE) {
            try {
                shutdownInput.getCheckpointer().checkpoint();
            } catch (ShutdownException | InvalidStateException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public void shutdownRequested(IRecordProcessorCheckpointer checkpointer) {
        try {
            checkpointer.checkpoint();
        } catch (ShutdownException | InvalidStateException e) {
            //
            // Swallow exception
            //
            e.printStackTrace();
        }
    }
}
```

**Untuk memigrasikan kelas RecordProcessor**

1. Ubah antarmuka dari `com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor` dan `com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IShutdownNotificationAware` menjadi `com.amazonaws.services.dynamodbv2.streamsadapter.processor.DynamoDBStreamsShardRecordProcessor` sebagai berikut:

   ```
   // import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor;
   // import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IShutdownNotificationAware;
   
   import com.amazonaws.services.dynamodbv2.streamsadapter.processor.DynamoDBStreamsShardRecordProcessor;
   ```

1. Perbarui pernyataan impor untuk `initialize` dan `processRecords` metode:

   ```
   // import com.amazonaws.services.kinesis.clientlibrary.types.InitializationInput;
   import software.amazon.kinesis.lifecycle.events.InitializationInput;
   
   // import com.amazonaws.services.kinesis.clientlibrary.types.ProcessRecordsInput;
   import com.amazonaws.services.dynamodbv2.streamsadapter.model.DynamoDBStreamsProcessRecordsInput;
   ```

1. Ganti `shutdownRequested` metode dengan metode baru berikut:`leaseLost`,`shardEnded`, dan`shutdownRequested`.

   ```
   //    @Override
   //    public void shutdownRequested(IRecordProcessorCheckpointer checkpointer) {
   //        //
   //        // This is moved to shardEnded(...) and shutdownRequested(ShutdownReauestedInput)
   //        //
   //        try {
   //            checkpointer.checkpoint();
   //        } catch (ShutdownException | InvalidStateException e) {
   //            //
   //            // Swallow exception
   //            //
   //            e.printStackTrace();
   //        }
   //    }
   
       @Override
       public void leaseLost(LeaseLostInput leaseLostInput) {
   
       }
   
       @Override
       public void shardEnded(ShardEndedInput shardEndedInput) {
           try {
               shardEndedInput.checkpointer().checkpoint();
           } catch (ShutdownException | InvalidStateException e) {
               //
               // Swallow the exception
               //
               e.printStackTrace();
           }
       }
   
       @Override
       public void shutdownRequested(ShutdownRequestedInput shutdownRequestedInput) {
           try {
               shutdownRequestedInput.checkpointer().checkpoint();
           } catch (ShutdownException | InvalidStateException e) {
               //
               // Swallow the exception
               //
               e.printStackTrace();
           }
       }
   ```

Berikut ini adalah versi terbaru dari kelas prosesor rekaman:

```
package com.amazonaws.codesamples;

import software.amazon.kinesis.exceptions.InvalidStateException;
import software.amazon.kinesis.exceptions.ShutdownException;
import software.amazon.kinesis.lifecycle.events.InitializationInput;
import software.amazon.kinesis.lifecycle.events.LeaseLostInput;
import com.amazonaws.services.dynamodbv2.streamsadapter.model.DynamoDBStreamsProcessRecordsInput;
import software.amazon.kinesis.lifecycle.events.ShardEndedInput;
import software.amazon.kinesis.lifecycle.events.ShutdownRequestedInput;
import software.amazon.dynamodb.streamsadapter.processor.DynamoDBStreamsShardRecordProcessor;
import software.amazon.dynamodb.streamsadapter.adapter.DynamoDBStreamsKinesisClientRecord;
import com.amazonaws.services.dynamodbv2.streamsadapter.processor.DynamoDBStreamsShardRecordProcessor;
import com.amazonaws.services.dynamodbv2.streamsadapter.adapter.DynamoDBStreamsClientRecord;
import software.amazon.awssdk.services.dynamodb.model.Record;

public class StreamsRecordProcessor implements DynamoDBStreamsShardRecordProcessor {

    @Override
    public void initialize(InitializationInput initializationInput) {
        
    }

    @Override
    public void processRecords(DynamoDBStreamsProcessRecordsInput processRecordsInput) {
        for (DynamoDBStreamsKinesisClientRecord record: processRecordsInput.records())
            Record ddbRecord = record.getRecord();
            // processing and checkpointing logic for the ddbRecord
        }
    }

    @Override
    public void leaseLost(LeaseLostInput leaseLostInput) {
        
    }

    @Override
    public void shardEnded(ShardEndedInput shardEndedInput) {
        try {
            shardEndedInput.checkpointer().checkpoint();
        } catch (ShutdownException | InvalidStateException e) {
            //
            // Swallow the exception
            //
            e.printStackTrace();
        }
    }

    @Override
    public void shutdownRequested(ShutdownRequestedInput shutdownRequestedInput) {
        try {
            shutdownRequestedInput.checkpointer().checkpoint();
        } catch (ShutdownException | InvalidStateException e) {
            //
            // Swallow the exception
            //
            e.printStackTrace();
        }
    }
}
```

**catatan**  
DynamoDB Streams Kinesis Adapter sekarang menggunakan model Record. SDKv2 Dalam SDKv2, `AttributeValue` objek kompleks (`BS`,`NS`, `M``L`,`SS`) tidak pernah mengembalikan null. Gunakan`hasBs()`,`hasNs()`,`hasM()`,`hasL()`, `hasSs()` metode untuk memverifikasi apakah nilai-nilai ini ada.

### Langkah 2: Migrasikan pabrik prosesor rekaman
<a name="step2-record-processor-factory"></a>

Pabrik prosesor rekaman bertanggung jawab untuk membuat prosesor rekaman ketika sewa diperoleh. Berikut ini adalah contoh pabrik KCL 1.x:

```
package com.amazonaws.codesamples;

import software.amazon.dynamodb.AmazonDynamoDB;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessorFactory;

public class StreamsRecordProcessorFactory implements IRecordProcessorFactory {
    
    @Override
    public IRecordProcessor createProcessor() {
        return new StreamsRecordProcessor(dynamoDBClient, tableName);
    }
}
```

**Untuk memigrasikan `RecordProcessorFactory`**
+ Ubah antarmuka yang diimplementasikan dari `com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessorFactory` ke`software.amazon.kinesis.processor.ShardRecordProcessorFactory`, sebagai berikut:

  ```
  // import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor;
  import software.amazon.kinesis.processor.ShardRecordProcessor;
  
  // import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessorFactory;
  import software.amazon.kinesis.processor.ShardRecordProcessorFactory;
  
  // public class TestRecordProcessorFactory implements IRecordProcessorFactory {
  public class StreamsRecordProcessorFactory implements ShardRecordProcessorFactory {
  
  Change the return signature for createProcessor.
  
  // public IRecordProcessor createProcessor() {
  public ShardRecordProcessor shardRecordProcessor() {
  ```

Berikut ini adalah contoh pabrik prosesor rekaman di 3.0:

```
package com.amazonaws.codesamples;

import software.amazon.kinesis.processor.ShardRecordProcessor;
import software.amazon.kinesis.processor.ShardRecordProcessorFactory;

public class StreamsRecordProcessorFactory implements ShardRecordProcessorFactory {

    @Override
    public ShardRecordProcessor shardRecordProcessor() {
        return new StreamsRecordProcessor();
    }
}
```

### Langkah 3: Migrasikan pekerja
<a name="step3-worker-migration"></a>

**Dalam versi 3.0 dari KCL, kelas baru, yang disebut **Scheduler**, menggantikan kelas Worker.** Berikut ini adalah contoh pekerja KCL 1.x:

```
final KinesisClientLibConfiguration config = new KinesisClientLibConfiguration(...)
final IRecordProcessorFactory recordProcessorFactory = new RecordProcessorFactory();
final Worker worker = StreamsWorkerFactory.createDynamoDbStreamsWorker(
        recordProcessorFactory,
        workerConfig,
        adapterClient,
        amazonDynamoDB,
        amazonCloudWatchClient);
```

**Untuk memigrasikan pekerja**

1. Ubah `import` pernyataan untuk `Worker` kelas ke pernyataan impor untuk `Scheduler` dan `ConfigsBuilder` kelas.

   ```
   // import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker;
   import software.amazon.kinesis.coordinator.Scheduler;
   import software.amazon.kinesis.common.ConfigsBuilder;
   ```

1. Impor `StreamTracker` dan ubah impor `StreamsWorkerFactory` ke`StreamsSchedulerFactory`.

   ```
   import software.amazon.kinesis.processor.StreamTracker;
   // import software.amazon.dynamodb.streamsadapter.StreamsWorkerFactory;
   import software.amazon.dynamodb.streamsadapter.StreamsSchedulerFactory;
   ```

1. Pilih posisi untuk memulai aplikasi. Bisa jadi `TRIM_HORIZON` atau`LATEST`.

   ```
   import software.amazon.kinesis.common.InitialPositionInStream;
   import software.amazon.kinesis.common.InitialPositionInStreamExtended;
   ```

1. Buat sebuah `StreamTracker` instance.

   ```
   StreamTracker streamTracker = StreamsSchedulerFactory.createSingleStreamTracker(
           streamArn,
           InitialPositionInStreamExtended.newInitialPosition(InitialPositionInStream.TRIM_HORIZON)
   );
   ```

1. Buat `AmazonDynamoDBStreamsAdapterClient` objek.

   ```
   import software.amazon.dynamodb.streamsadapter.AmazonDynamoDBStreamsAdapterClient; 
   import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
   import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
   
   ...
   
   AwsCredentialsProvider credentialsProvider = DefaultCredentialsProvider.create();
   
   AmazonDynamoDBStreamsAdapterClient adapterClient = new AmazonDynamoDBStreamsAdapterClient(
           credentialsProvider, awsRegion);
   ```

1. Buat `ConfigsBuilder` objek.

   ```
   import software.amazon.kinesis.common.ConfigsBuilder;
   
   ...
   ConfigsBuilder configsBuilder = new ConfigsBuilder(
                   streamTracker,
                   applicationName,
                   adapterClient,
                   dynamoDbAsyncClient,
                   cloudWatchAsyncClient,
                   UUID.randomUUID().toString(),
                   new StreamsRecordProcessorFactory());
   ```

1. Buat `Scheduler` menggunakan `ConfigsBuilder` seperti yang ditunjukkan pada contoh berikut:

   ```
   import java.util.UUID;
   
   import software.amazon.awssdk.regions.Region;
   import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
   import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
   import software.amazon.awssdk.services.kinesis.KinesisAsyncClient;
   
   import software.amazon.kinesis.common.KinesisClientUtil;
   import software.amazon.kinesis.coordinator.Scheduler;
   
   ...
   
                   
   DynamoDbAsyncClient dynamoClient = DynamoDbAsyncClient.builder().region(region).build();
   CloudWatchAsyncClient cloudWatchClient = CloudWatchAsyncClient.builder().region(region).build();
   
                   
   DynamoDBStreamsPollingConfig pollingConfig = new DynamoDBStreamsPollingConfig(adapterClient);
   pollingConfig.idleTimeBetweenReadsInMillis(idleTimeBetweenReadsInMillis);
   
   // Use ConfigsBuilder to configure settings
   RetrievalConfig retrievalConfig = configsBuilder.retrievalConfig();
   retrievalConfig.retrievalSpecificConfig(pollingConfig);
   
   CoordinatorConfig coordinatorConfig = configsBuilder.coordinatorConfig();
   coordinatorConfig.clientVersionConfig(CoordinatorConfig.ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X);
                   
   Scheduler scheduler = StreamsSchedulerFactory.createScheduler(
                   configsBuilder.checkpointConfig(),
                   coordinatorConfig,
                   configsBuilder.leaseManagementConfig(),
                   configsBuilder.lifecycleConfig(),
                   configsBuilder.metricsConfig(),
                   configsBuilder.processorConfig(),
                   retrievalConfig,
                   adapterClient
           );
   ```

**penting**  
`CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X`Pengaturan mempertahankan kompatibilitas antara DynamoDB Streams Kinesis Adapter untuk KCL v3 dan KCL v1, bukan antara KCL v2 dan v3.

### Langkah 4: Ikhtisar dan rekomendasi konfigurasi KCL 3.x
<a name="step4-configuration-migration"></a>

[Untuk penjelasan rinci tentang konfigurasi yang diperkenalkan setelah KCL 1.x yang relevan di KCL 3.x lihat konfigurasi KCL dan [konfigurasi klien migrasi KCL](https://docs.aws.amazon.com//streams/latest/dev/kcl-configuration.html).](https://docs.aws.amazon.com//streams/latest/dev/kcl-migration.html#client-configuration)

**penting**  
Alih-alih langsung membuat objek`checkpointConfig`,,,`coordinatorConfig`, `processorConfig` dan `leaseManagementConfig` `metricsConfig``retrievalConfig`, kami sarankan menggunakan `ConfigsBuilder` untuk mengatur konfigurasi di KCL 3.x dan versi yang lebih baru untuk menghindari masalah inisialisasi Scheduler. `ConfigsBuilder`menyediakan cara yang lebih fleksibel dan dapat dipelihara untuk mengkonfigurasi aplikasi KCL Anda.

#### Konfigurasi dengan nilai default pembaruan di KCL 3.x
<a name="kcl3-configuration-overview"></a>

`billingMode`  
Dalam KCL versi 1.x, nilai default untuk `billingMode` diatur ke. `PROVISIONED` Namun, dengan KCL versi 3.x, defaultnya `billingMode` adalah `PAY_PER_REQUEST` (mode on-demand). Kami menyarankan Anda menggunakan mode kapasitas sesuai permintaan untuk tabel sewa Anda untuk secara otomatis menyesuaikan kapasitas berdasarkan penggunaan Anda. Untuk panduan tentang penggunaan kapasitas yang disediakan untuk tabel sewa Anda, lihat [Praktik terbaik untuk tabel sewa dengan mode](https://docs.aws.amazon.com//streams/latest/dev/kcl-migration-lease-table.html) kapasitas yang disediakan.

`idleTimeBetweenReadsInMillis`  
Dalam KCL versi 1.x, nilai default untuk diatur ke `idleTimeBetweenReadsInMillis` adalah 1.000 (atau 1 detik). KCL versi 3.x menetapkan nilai default `dleTimeBetweenReadsInMillis` untuk i menjadi 1.500 (atau 1,5 detik), tetapi Amazon DynamoDB Streams Kinesis Adapter mengganti nilai default menjadi 1.000 (atau 1 detik).

#### Konfigurasi baru di KCL 3.x
<a name="kcl3-new-configs"></a>

`leaseAssignmentIntervalMillis`  
Konfigurasi ini mendefinisikan interval waktu sebelum pecahan yang baru ditemukan mulai diproses, dan dihitung sebagai 1,5 ×. `leaseAssignmentIntervalMillis` Jika pengaturan ini tidak dikonfigurasi secara eksplisit, interval waktu default menjadi 1,5 ×. `failoverTimeMillis` Memproses pecahan baru melibatkan pemindaian tabel sewa dan menanyakan indeks sekunder global (GSI) pada tabel sewa. Menurunkan `leaseAssignmentIntervalMillis` peningkatan frekuensi operasi pemindaian dan kueri ini, menghasilkan biaya DynamoDB yang lebih tinggi. Kami merekomendasikan pengaturan nilai ini ke 2000 (atau 2 detik) untuk meminimalkan keterlambatan dalam memproses pecahan baru.

`shardConsumerDispatchPollIntervalMillis`  
Konfigurasi ini mendefinisikan interval antara jajak pendapat berturut-turut oleh konsumen shard untuk memicu transisi status. Di KCL versi 1.x, perilaku ini dikendalikan oleh `idleTimeInMillis` parameter, yang tidak diekspos sebagai pengaturan yang dapat dikonfigurasi. Dengan KCL versi 3.x, kami sarankan untuk mengatur konfigurasi ini agar sesuai dengan nilai yang digunakan ` idleTimeInMillis` dalam pengaturan KCL versi 1.x Anda.

### Langkah 5: Migrasi dari KCL 2.x ke KCL 3.x
<a name="step5-kcl2-to-kcl3"></a>

Untuk memastikan kelancaran transisi dan kompatibilitas dengan versi Kinesis Client Library (KCL) terbaru, ikuti langkah 5-8 dalam petunjuk panduan migrasi untuk [meningkatkan dari KCL 2.x ke KCL 3.x](https://docs.aws.amazon.com//streams/latest/dev/kcl-migration-from-2-3.html#kcl-migration-from-2-3-worker-metrics).

[Untuk masalah pemecahan masalah umum KCL 3.x, lihat Memecahkan masalah aplikasi konsumen KCL.](https://docs.aws.amazon.com//streams/latest/dev/troubleshooting-consumers.html)

# Putar kembali ke versi KCL sebelumnya
<a name="kcl-migration-rollback"></a>

Topik ini menjelaskan cara mengembalikan aplikasi konsumen Anda ke versi KCL sebelumnya. Proses roll-back terdiri dari dua langkah:

1. Jalankan [Alat Migrasi KCL](https://github.com/awslabs/amazon-kinesis-client/blob/master/amazon-kinesis-client/scripts/KclMigrationTool.py).

1. Menerapkan ulang kode versi KCL sebelumnya.

## Langkah 1: Jalankan Alat Migrasi KCL
<a name="kcl-migration-rollback-step1"></a>

Ketika Anda perlu memutar kembali ke versi KCL sebelumnya, Anda harus menjalankan Alat Migrasi KCL. Alat ini melakukan dua tugas penting:
+ Ini menghapus tabel metadata yang disebut tabel metrik pekerja dan indeks sekunder global pada tabel sewa di DynamoDB. Artefak ini dibuat oleh KCL 3.x tetapi tidak diperlukan saat Anda memutar kembali ke versi sebelumnya.
+ Itu membuat semua pekerja berjalan dalam mode yang kompatibel dengan KCL 1.x dan mulai menggunakan algoritma load balancing yang digunakan dalam versi KCL sebelumnya. Jika Anda memiliki masalah dengan algoritme penyeimbangan beban baru di KCL 3.x, ini akan segera mengurangi masalah.

**penting**  
Tabel status koordinator di DynamoDB harus ada dan tidak boleh dihapus selama proses migrasi, rollback, dan rollforward.

**catatan**  
Sangat penting bahwa semua pekerja dalam aplikasi konsumen Anda menggunakan algoritma load balancing yang sama pada waktu tertentu. Alat Migrasi KCL memastikan bahwa semua pekerja di aplikasi konsumen KCL 3.x Anda beralih ke mode yang kompatibel dengan KCL 1.x sehingga semua pekerja menjalankan algoritma load balancing yang sama selama rollback aplikasi ke versi KCL sebelumnya.

Anda dapat mengunduh [Alat Migrasi KCL](https://github.com/awslabs/amazon-kinesis-client/blob/master/amazon-kinesis-client/scripts/KclMigrationTool.py) di direktori skrip repositori [ GitHubKCL](https://github.com/awslabs/amazon-kinesis-client/tree/master). Jalankan skrip dari pekerja atau host dengan izin yang sesuai untuk menulis ke tabel status koordinator, tabel metrik pekerja, dan tabel sewa. Pastikan [izin IAM](https://docs.aws.amazon.com/streams/latest/dev/kcl-iam-permissions.html) yang sesuai dikonfigurasi untuk aplikasi konsumen KCL. Jalankan skrip hanya sekali per aplikasi KCL menggunakan perintah yang ditentukan:

```
python3 ./KclMigrationTool.py --region region --mode rollback [--application_name applicationName] [--lease_table_name leaseTableName] [--coordinator_state_table_name coordinatorStateTableName] [--worker_metrics_table_name workerMetricsTableName]
```

### Parameter
<a name="kcl-migration-rollback-parameters"></a>

`--region`  
Ganti *region* dengan Anda Wilayah AWS.

`--application_name`  
Parameter ini diperlukan jika Anda menggunakan nama default untuk tabel metadata DynamoDB Anda (tabel sewa, tabel status koordinator, dan tabel metrik pekerja). Jika Anda telah menentukan nama kustom untuk tabel ini, Anda dapat menghilangkan parameter ini. Ganti *applicationName* dengan nama aplikasi KCL Anda yang sebenarnya. Alat ini menggunakan nama ini untuk mendapatkan nama tabel default jika nama kustom tidak disediakan.

`--lease_table_name`  
Parameter ini diperlukan ketika Anda telah menetapkan nama kustom untuk tabel sewa dalam konfigurasi KCL Anda. Jika Anda menggunakan nama tabel default, Anda dapat menghilangkan parameter ini. Ganti *leaseTableName* dengan nama tabel kustom yang Anda tentukan untuk tabel sewa Anda.

`--coordinator_state_table_name`  
Parameter ini diperlukan ketika Anda telah menetapkan nama kustom untuk tabel status koordinator dalam konfigurasi KCL Anda. Jika Anda menggunakan nama tabel default, Anda dapat menghilangkan parameter ini. Ganti *coordinatorStateTableName* dengan nama tabel kustom yang Anda tentukan untuk tabel status koordinator Anda.

`--worker_metrics_table_name`  
Parameter ini diperlukan ketika Anda telah menetapkan nama khusus untuk tabel metrik pekerja dalam konfigurasi KCL Anda. Jika Anda menggunakan nama tabel default, Anda dapat menghilangkan parameter ini. Ganti *workerMetricsTableName* dengan nama tabel kustom yang Anda tentukan untuk tabel metrik pekerja Anda.

## Langkah 2: Menerapkan ulang kode dengan versi KCL sebelumnya
<a name="kcl-migration-rollback-step2"></a>

**penting**  
Setiap penyebutan versi 2.x dalam output yang dihasilkan oleh Alat Migrasi KCL harus ditafsirkan sebagai mengacu pada KCL versi 1.x. Menjalankan skrip tidak melakukan rollback lengkap, itu hanya mengalihkan algoritma load balancing ke yang digunakan dalam KCL versi 1.x.

Setelah menjalankan KCL Migration Tool untuk rollback, Anda akan melihat salah satu pesan berikut:

Pesan 1  
“Rollback selesai. Aplikasi Anda menjalankan fungsionalitas yang kompatibel dengan 2x. Harap kembalikan ke binari aplikasi Anda sebelumnya dengan menerapkan kode dengan versi KCL Anda sebelumnya.”  
**Tindakan yang diperlukan:** Ini berarti pekerja Anda berjalan dalam mode kompatibel KCL 1.x. Menerapkan ulang kode dengan versi KCL sebelumnya ke pekerja Anda.

Pesan 2  
“Rollback selesai. Aplikasi KCL Anda menjalankan fungsionalitas 3x dan akan mengembalikan ke fungsionalitas yang kompatibel dengan 2x. Jika Anda tidak melihat mitigasi setelah periode waktu yang singkat, harap kembalikan ke binari aplikasi Anda sebelumnya dengan menerapkan kode dengan versi KCL Anda sebelumnya.  
**Tindakan yang diperlukan:** Ini berarti pekerja Anda berjalan dalam mode KCL 3.x dan Alat Migrasi KCL mengalihkan semua pekerja ke mode yang kompatibel dengan KCL 1.x. Menerapkan ulang kode dengan versi KCL sebelumnya ke pekerja Anda.

Pesan 3  
“Aplikasi sudah digulung kembali. KCLv3 Sumber daya apa pun yang dapat dihapus dibersihkan untuk menghindari biaya hingga aplikasi dapat digulirkan dengan migrasi.  
**Tindakan yang diperlukan:** Ini berarti bahwa pekerja Anda sudah diputar kembali untuk berjalan dalam mode kompatibel KCL 1.x. Menerapkan ulang kode dengan versi KCL sebelumnya ke pekerja Anda.

# Gulung maju ke KCL 3.x setelah rollback
<a name="kcl-migration-rollforward"></a>

Topik ini menjelaskan cara meneruskan aplikasi konsumen Anda ke KCL 3.x setelah rollback. Ketika Anda perlu maju, Anda harus menyelesaikan proses dua langkah:

1. Jalankan [Alat Migrasi KCL](https://github.com/awslabs/amazon-kinesis-client/blob/master/amazon-kinesis-client/scripts/KclMigrationTool.py).

1. Terapkan kode dengan KCL 3.x.

## Langkah 1: Jalankan Alat Migrasi KCL
<a name="kcl-migration-rollforward-step1"></a>

Jalankan KCL Migration Tool dengan perintah berikut untuk maju ke KCL 3.x:

```
python3 ./KclMigrationTool.py --region region --mode rollforward [--application_name applicationName] [--coordinator_state_table_name coordinatorStateTableName]
```

### Parameter
<a name="kcl-migration-rollforward-parameters"></a>

`--region`  
Ganti *region* dengan Anda Wilayah AWS.

`--application_name`  
Parameter ini diperlukan jika Anda menggunakan nama default untuk tabel status koordinator Anda. Jika Anda telah menentukan nama kustom untuk tabel status koordinator, Anda dapat menghilangkan parameter ini. Ganti *applicationName* dengan nama aplikasi KCL Anda yang sebenarnya. Alat ini menggunakan nama ini untuk mendapatkan nama tabel default jika nama kustom tidak disediakan.

`--coordinator_state_table_name`  
Parameter ini diperlukan ketika Anda telah menetapkan nama kustom untuk tabel status koordinator dalam konfigurasi KCL Anda. Jika Anda menggunakan nama tabel default, Anda dapat menghilangkan parameter ini. Ganti *coordinatorStateTableName* dengan nama tabel kustom yang Anda tentukan untuk tabel status koordinator Anda.

Setelah Anda menjalankan alat migrasi dalam mode roll-forward, KCL membuat sumber daya DynamoDB berikut yang diperlukan untuk KCL 3.x:
+ Indeks Sekunder Global pada tabel sewa
+ Tabel metrik pekerja

## Langkah 2: Menyebarkan kode dengan KCL 3.x
<a name="kcl-migration-rollforward-step2"></a>

Setelah menjalankan Alat Migrasi KCL untuk maju, terapkan kode Anda dengan KCL 3.x ke pekerja Anda. Untuk menyelesaikan migrasi, lihat [Langkah 8: Selesaikan migrasi](https://docs.aws.amazon.com/streams/latest/dev/kcl-migration-from-2-3.html#kcl-migration-from-2-3-finish).

# Panduan: Adaptor DynamoDB Streams Kinesis
<a name="Streams.KCLAdapter.Walkthrough"></a>

Bagian ini adalah panduan aplikasi Java yang menggunakan Perpustakaan Klien Amazon Kinesis dan Adaptor Amazon DynamoDB Streams Kinesis. Aplikasi ini memperlihatkan contoh replikasi data, di mana aktivitas penulisan dari satu tabel diterapkan ke tabel kedua, dengan konten kedua tabel tetap sinkron. Untuk kode sumber, lihat [Program lengkap: Adaptor DynamoDB Streams Kinesis](Streams.KCLAdapter.Walkthrough.CompleteProgram.md).

Program ini melakukan hal berikut:

1. Menciptakan dua tabel DynamoDB bernama `KCL-Demo-src` dan `KCL-Demo-dst`. Masing-masing tabel ini memiliki stream yang diaktifkan.

1. Menghasilkan aktivitas pembaruan dalam tabel sumber dengan menambahkan, memperbarui, dan menghapus item. Hal ini menyebabkan data akan ditulis ke stream tabel.

1. Membaca catatan dari stream, merekonstruksinya sebagai permintaan DynamoDB, dan menerapkan permintaan ke tabel tujuan.

1. Memindai tabel sumber dan tujuan untuk memastikan bahwa isinya identik.

1. Membersihkan dengan menghapus tabel.

Langkah-langkah ini dijelaskan di bagian berikut, dan aplikasi lengkap ditampilkan di akhir panduan.

**Topics**
+ [Langkah 1: Buat tabel DynamoDB](#Streams.KCLAdapter.Walkthrough.Step1)
+ [Langkah 2: Hasilkan aktivitas pembaruan di tabel sumber](#Streams.KCLAdapter.Walkthrough.Step2)
+ [Langkah 3: Proses alirannya](#Streams.KCLAdapter.Walkthrough.Step3)
+ [Langkah 4: Pastikan bahwa kedua tabel memiliki isi identik](#Streams.KCLAdapter.Walkthrough.Step4)
+ [Langkah 5: Bersihkan](#Streams.KCLAdapter.Walkthrough.Step5)
+ [Program lengkap: Adaptor DynamoDB Streams Kinesis](Streams.KCLAdapter.Walkthrough.CompleteProgram.md)

## Langkah 1: Buat tabel DynamoDB
<a name="Streams.KCLAdapter.Walkthrough.Step1"></a>

Langkah pertama adalah membuat dua tabel DynamoDB—tabel sumber dan tabel tujuan. `StreamViewType` pada aliran tabel sumber adalah `NEW_IMAGE`. Ini berarti bahwa setiap kali item diubah dalam tabel ini, gambar "setelah" item tersebut ditulis ke aliran. Dengan cara ini, aliran melacak semua aktivitas penulisan di tabel.

Contoh berikut menunjukkan kode yang digunakan untuk membuat kedua tabel.

```
java.util.List<AttributeDefinition> attributeDefinitions = new ArrayList<AttributeDefinition>();
attributeDefinitions.add(new AttributeDefinition().withAttributeName("Id").withAttributeType("N"));

java.util.List<KeySchemaElement> keySchema = new ArrayList<KeySchemaElement>();
keySchema.add(new KeySchemaElement().withAttributeName("Id").withKeyType(KeyType.HASH)); // Partition
                                                                                         // key

ProvisionedThroughput provisionedThroughput = new ProvisionedThroughput().withReadCapacityUnits(2L)
    .withWriteCapacityUnits(2L);

StreamSpecification streamSpecification = new StreamSpecification();
streamSpecification.setStreamEnabled(true);
streamSpecification.setStreamViewType(StreamViewType.NEW_IMAGE);
CreateTableRequest createTableRequest = new CreateTableRequest().withTableName(tableName)
    .withAttributeDefinitions(attributeDefinitions).withKeySchema(keySchema)
    .withProvisionedThroughput(provisionedThroughput).withStreamSpecification(streamSpecification);
```

## Langkah 2: Hasilkan aktivitas pembaruan di tabel sumber
<a name="Streams.KCLAdapter.Walkthrough.Step2"></a>

Langkah selanjutnya adalah menghasilkan beberapa aktivitas menulis pada tabel sumber. Saat aktivitas ini berlangsung, aliran tabel sumber juga diperbarui hampir secara waktu nyata.

Aplikasi ini mendefinisikan kelas pembantu dengan metode yang memanggil operasi `PutItem`, `UpdateItem`, dan API `DeleteItem` untuk menulis data. Contoh kode berikut menunjukkan bagaimana metode ini digunakan.

```
StreamsAdapterDemoHelper.putItem(dynamoDBClient, tableName, "101", "test1");
StreamsAdapterDemoHelper.updateItem(dynamoDBClient, tableName, "101", "test2");
StreamsAdapterDemoHelper.deleteItem(dynamoDBClient, tableName, "101");
StreamsAdapterDemoHelper.putItem(dynamoDBClient, tableName, "102", "demo3");
StreamsAdapterDemoHelper.updateItem(dynamoDBClient, tableName, "102", "demo4");
StreamsAdapterDemoHelper.deleteItem(dynamoDBClient, tableName, "102");
```

## Langkah 3: Proses alirannya
<a name="Streams.KCLAdapter.Walkthrough.Step3"></a>

Sekarang program mulai memproses aliran. Adaptor Kinesis DynamoDB Streams bertindak sebagai lapisan transparan antara KCL dan titik akhir DynamoDB Streams, sehingga kode dapat sepenuhnya menggunakan KCL daripada harus melakukan panggilan DynamoDB Streams tingkat rendah. Program ini melakukan tugas-tugas berikut:
+ Ini mendefinisikan kelas prosesor catatan, `StreamsRecordProcessor`, dengan metode yang sesuai dengan definisi antarmuka KCL: `initialize`, `processRecords`, dan `shutdown`. Metode `processRecords` berisi logika yang diperlukan untuk membaca dari stream tabel sumber dan menulis ke tabel tujuan.
+ Ini mendefinisikan sebuah pabrik kelas untuk kelas prosesor catatan (`StreamsRecordProcessorFactory`). Hal ini diperlukan untuk program Java yang menggunakan KCL.
+ Ini menginstanskan KCL `Worker` baru, yang terkait dengan pabrik kelas.
+ Ini mematikan `Worker` saat pemrosesan catatan selesai.

Secara opsional, aktifkan mode catch-up dalam konfigurasi Adaptor KCL Streams Anda untuk secara otomatis menskalakan laju panggilan GetRecords API sebesar 3x (default) saat kelambatan pemrosesan streaming melebihi satu menit (default), membantu konsumen streaming Anda menangani lonjakan throughput tinggi di tabel Anda.

Untuk mempelajari lebih lanjut tentang definisi antarmuka KCL, lihat [Mengembangkan konsumen menggunakan Kinesis client library](https://docs.aws.amazon.com/kinesis/latest/dev/developing-consumers-with-kcl.html) di *Panduan Pengembang Amazon Kinesis Data Streams*. 

Contoh kode berikut menunjukkan loop utama dalam `StreamsRecordProcessor`. Pernyataan `case` menentukan apa tindakan apa yang harus dilakukan, berdasarkan `OperationType` yang muncul dalam catatan stream.

```
for (Record record : records) {
    String data = new String(record.getData().array(), Charset.forName("UTF-8"));
    System.out.println(data);
    if (record instanceof RecordAdapter) {
                software.amazon.dynamodb.model.Record streamRecord = ((RecordAdapter) record)
                    .getInternalObject();

                switch (streamRecord.getEventName()) {
                    case "INSERT":
                    case "MODIFY":
                        StreamsAdapterDemoHelper.putItem(dynamoDBClient, tableName,
                            streamRecord.getDynamodb().getNewImage());
                        break;
                    case "REMOVE":
                        StreamsAdapterDemoHelper.deleteItem(dynamoDBClient, tableName,
                            streamRecord.getDynamodb().getKeys().get("Id").getN());
                }
    }
    checkpointCounter += 1;
    if (checkpointCounter % 10 == 0) {
        try {
            checkpointer.checkpoint();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

## Langkah 4: Pastikan bahwa kedua tabel memiliki isi identik
<a name="Streams.KCLAdapter.Walkthrough.Step4"></a>

Pada titik ini, isi sumber dan tujuan tabel tersinkronisasi. Aplikasi menerbitkan permintaan `Scan` terhadap kedua tabel untuk memverifikasi bahwa isinya, pada kenyataannya, identik.

Kelas `DemoHelper` berisi metode `ScanTable` yang memanggil API `Scan` tingkat rendah. Contoh berikut menunjukkan cara penggunaannya.

```
if (StreamsAdapterDemoHelper.scanTable(dynamoDBClient, srcTable).getItems()
    .equals(StreamsAdapterDemoHelper.scanTable(dynamoDBClient, destTable).getItems())) {
    System.out.println("Scan result is equal.");
}
else {
    System.out.println("Tables are different!");
}
```

## Langkah 5: Bersihkan
<a name="Streams.KCLAdapter.Walkthrough.Step5"></a>

Demo selesai, sehingga aplikasi menghapus tabel sumber dan tujuan. Lihat contoh kode berikut. Bahkan setelah tabel dihapus, alirannya tetap tersedia hingga 24 jam, setelah itu tabel akan dihapus secara otomatis.

```
dynamoDBClient.deleteTable(new DeleteTableRequest().withTableName(srcTable));
dynamoDBClient.deleteTable(new DeleteTableRequest().withTableName(destTable));
```

# Program lengkap: Adaptor DynamoDB Streams Kinesis
<a name="Streams.KCLAdapter.Walkthrough.CompleteProgram"></a>

Berikut ini adalah program Java lengkap yang melakukan tugas yang dijelaskan dalam [Panduan: Adaptor DynamoDB Streams Kinesis](Streams.KCLAdapter.Walkthrough.md). Saat Anda menjalankannya, Anda akan melihat output yang serupa dengan yang seperti berikut.

```
Creating table KCL-Demo-src
Creating table KCL-Demo-dest
Table is active.
Creating worker for stream: arn:aws:dynamodb:us-west-2:111122223333:table/KCL-Demo-src/stream/2015-05-19T22:48:56.601
Starting worker...
Scan result is equal.
Done.
```

**penting**  
 Untuk menjalankan program ini, pastikan bahwa aplikasi klien memiliki akses ke DynamoDB dan CloudWatch Amazon menggunakan kebijakan. Untuk informasi selengkapnya, lihat [Kebijakan berbasis identitas untuk DynamoDB](security_iam_service-with-iam.md#security_iam_service-with-iam-id-based-policies). 

Kode sumber terdiri dari empat `.java` file. Untuk membangun program ini, tambahkan dependensi berikut, yang mencakup Amazon Kinesis Client Library (KCL) 3.x dan SDK AWS for Java v2 sebagai dependensi transitif:

------
#### [ Maven ]

```
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>dynamodb-streams-kinesis-adapter</artifactId>
    <version>2.1.0</version>
</dependency>
```

------
#### [ Gradle ]

```
implementation 'com.amazonaws:dynamodb-streams-kinesis-adapter:2.1.0'
```

------

File sumbernya adalah:
+ `StreamsAdapterDemo.java`
+ `StreamsRecordProcessor.java`
+ `StreamsRecordProcessorFactory.java`
+ `StreamsAdapterDemoHelper.java`

## StreamsAdapterDemo.jawa
<a name="Streams.KCLAdapter.Walkthrough.CompleteProgram.StreamsAdapterDemo"></a>

```
package com.amazonaws.codesamples;

import com.amazonaws.services.dynamodbv2.streamsadapter.AmazonDynamoDBStreamsAdapterClient;
import com.amazonaws.services.dynamodbv2.streamsadapter.StreamsSchedulerFactory;
import com.amazonaws.services.dynamodbv2.streamsadapter.polling.DynamoDBStreamsPollingConfig;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.kinesis.common.ConfigsBuilder;
import software.amazon.kinesis.common.InitialPositionInStream;
import software.amazon.kinesis.common.InitialPositionInStreamExtended;
import software.amazon.kinesis.coordinator.Scheduler;
import software.amazon.kinesis.processor.ShardRecordProcessorFactory;
import software.amazon.kinesis.processor.StreamTracker;
import software.amazon.kinesis.retrieval.RetrievalConfig;

public class StreamsAdapterDemo {

    private static DynamoDbAsyncClient dynamoDbAsyncClient;
    private static CloudWatchAsyncClient cloudWatchAsyncClient;
    private static AmazonDynamoDBStreamsAdapterClient amazonDynamoDbStreamsAdapterClient;

    private static String tablePrefix = "KCL-Demo";
    private static String streamArn;

    private static Region region = Region.US_EAST_1;
    private static AwsCredentialsProvider credentialsProvider = DefaultCredentialsProvider.create();

    public static void main( String[] args ) throws Exception {
        System.out.println("Starting demo...");
        dynamoDbAsyncClient = DynamoDbAsyncClient.builder()
                .credentialsProvider(credentialsProvider)
                .region(region)
                .build();
        cloudWatchAsyncClient = CloudWatchAsyncClient.builder()
                .credentialsProvider(credentialsProvider)
                .region(region)
                .build();
        amazonDynamoDbStreamsAdapterClient = new AmazonDynamoDBStreamsAdapterClient(credentialsProvider, region);

        String srcTable = tablePrefix + "-src";
        String destTable = tablePrefix + "-dest";

        setUpTables();

        StreamTracker streamTracker = StreamsSchedulerFactory.createSingleStreamTracker(streamArn,
                InitialPositionInStreamExtended.newInitialPosition(InitialPositionInStream.TRIM_HORIZON));

        ShardRecordProcessorFactory shardRecordProcessorFactory =
                new StreamsAdapterDemoProcessorFactory(dynamoDbAsyncClient, destTable);

        ConfigsBuilder configsBuilder = new ConfigsBuilder(
                streamTracker,
                "streams-adapter-demo",
                amazonDynamoDbStreamsAdapterClient,
                dynamoDbAsyncClient,
                cloudWatchAsyncClient,
                "streams-demo-worker",
                shardRecordProcessorFactory
        );

        DynamoDBStreamsPollingConfig pollingConfig = new DynamoDBStreamsPollingConfig(amazonDynamoDbStreamsAdapterClient);
        RetrievalConfig retrievalConfig = configsBuilder.retrievalConfig();
        retrievalConfig.retrievalSpecificConfig(pollingConfig);

        System.out.println("Creating scheduler for stream " + streamArn);
        Scheduler scheduler = StreamsSchedulerFactory.createScheduler(
                configsBuilder.checkpointConfig(),
                configsBuilder.coordinatorConfig(),
                configsBuilder.leaseManagementConfig(),
                configsBuilder.lifecycleConfig(),
                configsBuilder.metricsConfig(),
                configsBuilder.processorConfig(),
                retrievalConfig,
                amazonDynamoDbStreamsAdapterClient
        );

        System.out.println("Starting scheduler...");
        Thread t = new Thread(scheduler);
        t.start();

        Thread.sleep(250000);

        System.out.println("Stopping scheduler...");
        scheduler.shutdown();
        t.join();

        if (StreamsAdapterDemoHelper.scanTable(dynamoDbAsyncClient, srcTable).items()
                .equals(StreamsAdapterDemoHelper.scanTable(dynamoDbAsyncClient, destTable).items())) {
            System.out.println("Scan result is equal.");
        } else {
            System.out.println("Tables are different!");
        }

        System.out.println("Done.");
        cleanupAndExit(0);
    }

    private static void setUpTables() {
        String srcTable = tablePrefix + "-src";
        String destTable = tablePrefix + "-dest";
        streamArn = StreamsAdapterDemoHelper.createTable(dynamoDbAsyncClient, srcTable);
        StreamsAdapterDemoHelper.createTable(dynamoDbAsyncClient, destTable);

        awaitTableCreation(srcTable);

        performOps(srcTable);
    }

    private static void awaitTableCreation(String tableName) {
        Integer retries = 0;
        Boolean created = false;
        while (!created && retries < 100) {
            DescribeTableResponse result = StreamsAdapterDemoHelper.describeTable(dynamoDbAsyncClient, tableName);
            created = result.table().tableStatusAsString().equals("ACTIVE");
            if (created) {
                System.out.println("Table is active.");
                return;
            } else {
                retries++;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // do nothing
                }
            }
        }
        System.out.println("Timeout after table creation. Exiting...");
        cleanupAndExit(1);
    }

    private static void performOps(String tableName) {
        StreamsAdapterDemoHelper.putItem(dynamoDbAsyncClient, tableName, "101", "test1");
        StreamsAdapterDemoHelper.updateItem(dynamoDbAsyncClient, tableName, "101", "test2");
        StreamsAdapterDemoHelper.deleteItem(dynamoDbAsyncClient, tableName, "101");
        StreamsAdapterDemoHelper.putItem(dynamoDbAsyncClient, tableName, "102", "demo3");
        StreamsAdapterDemoHelper.updateItem(dynamoDbAsyncClient, tableName, "102", "demo4");
        StreamsAdapterDemoHelper.deleteItem(dynamoDbAsyncClient, tableName, "102");
    }

    private static void cleanupAndExit(Integer returnValue) {
        String srcTable = tablePrefix + "-src";
        String destTable = tablePrefix + "-dest";
        dynamoDbAsyncClient.deleteTable(DeleteTableRequest.builder().tableName(srcTable).build());
        dynamoDbAsyncClient.deleteTable(DeleteTableRequest.builder().tableName(destTable).build());
        System.exit(returnValue);
    }
}
```

## StreamsRecordProcessor.jawa
<a name="Streams.KCLAdapter.Walkthrough.CompleteProgram.StreamsRecordProcessor"></a>

```
package com.amazonaws.codesamples;

import com.amazonaws.services.dynamodbv2.streamsadapter.adapter.DynamoDBStreamsClientRecord;
import com.amazonaws.services.dynamodbv2.streamsadapter.model.DynamoDBStreamsProcessRecordsInput;
import com.amazonaws.services.dynamodbv2.streamsadapter.processor.DynamoDBStreamsShardRecordProcessor;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.model.Record;
import software.amazon.kinesis.exceptions.InvalidStateException;
import software.amazon.kinesis.exceptions.ShutdownException;
import software.amazon.kinesis.lifecycle.events.InitializationInput;
import software.amazon.kinesis.lifecycle.events.LeaseLostInput;
import software.amazon.kinesis.lifecycle.events.ShardEndedInput;
import software.amazon.kinesis.lifecycle.events.ShutdownRequestedInput;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class StreamsRecordProcessor implements DynamoDBStreamsShardRecordProcessor {

    private Integer checkpointCounter;

    private final DynamoDbAsyncClient dynamoDbAsyncClient;
    private final String tableName;

    public StreamsRecordProcessor(DynamoDbAsyncClient dynamoDbAsyncClient, String tableName) {
        this.dynamoDbAsyncClient = dynamoDbAsyncClient;
        this.tableName = tableName;
    }

    @Override
    public void initialize(InitializationInput initializationInput) {
        this.checkpointCounter = 0;
    }

    @Override
    public void processRecords(DynamoDBStreamsProcessRecordsInput dynamoDBStreamsProcessRecordsInput) {
        for (DynamoDBStreamsClientRecord record: dynamoDBStreamsProcessRecordsInput.records()) {
            String data = new String(record.data().array(), StandardCharsets.UTF_8);
            System.out.println(data);
            Record streamRecord = record.getRecord();

            switch (streamRecord.eventName()) {
                case INSERT:
                case MODIFY:
                    StreamsAdapterDemoHelper.putItem(dynamoDbAsyncClient, tableName,
                            streamRecord.dynamodb().newImage());
                case REMOVE:
                    StreamsAdapterDemoHelper.deleteItem(dynamoDbAsyncClient, tableName,
                            streamRecord.dynamodb().keys().get("Id").n());
            }
            checkpointCounter += 1;
            if (checkpointCounter % 10 == 0) {
                try {
                    dynamoDBStreamsProcessRecordsInput.checkpointer().checkpoint();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void leaseLost(LeaseLostInput leaseLostInput) {
        System.out.println("Lease Lost");
    }

    @Override
    public void shardEnded(ShardEndedInput shardEndedInput) {
        try {
            shardEndedInput.checkpointer().checkpoint();
        } catch (ShutdownException | InvalidStateException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void shutdownRequested(ShutdownRequestedInput shutdownRequestedInput) {
        try {
            shutdownRequestedInput.checkpointer().checkpoint();
        } catch (ShutdownException | InvalidStateException e) {
            e.printStackTrace();
        }
    }
}
```

## StreamsRecordProcessorFactory.jawa
<a name="Streams.KCLAdapter.Walkthrough.CompleteProgram.StreamsRecordProcessorFactory"></a>

```
package com.amazonaws.codesamples;

import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.kinesis.processor.ShardRecordProcessor;
import software.amazon.kinesis.processor.ShardRecordProcessorFactory;

public class StreamsAdapterDemoProcessorFactory implements ShardRecordProcessorFactory {
    private final String tableName;
    private final DynamoDbAsyncClient dynamoDbAsyncClient;

    public StreamsAdapterDemoProcessorFactory(DynamoDbAsyncClient asyncClient, String tableName) {
        this.tableName = tableName;
        this.dynamoDbAsyncClient = asyncClient;
    }

    @Override
    public ShardRecordProcessor shardRecordProcessor() {
        return new StreamsRecordProcessor(dynamoDbAsyncClient, tableName);
    }
}
```

## StreamsAdapterDemoHelper.jawa
<a name="Streams.KCLAdapter.Walkthrough.CompleteProgram.StreamsAdapterDemoHelper"></a>

```
package com.amazonaws.codesamples;

import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.CreateTableResponse;
import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
import software.amazon.awssdk.services.dynamodb.model.KeyType;
import software.amazon.awssdk.services.dynamodb.model.OnDemandThroughput;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.ResourceInUseException;
import software.amazon.awssdk.services.dynamodb.model.ScanRequest;
import software.amazon.awssdk.services.dynamodb.model.ScanResponse;
import software.amazon.awssdk.services.dynamodb.model.StreamSpecification;
import software.amazon.awssdk.services.dynamodb.model.StreamViewType;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class StreamsAdapterDemoHelper {

    /**
     * @return StreamArn
     */
    public static String createTable(DynamoDbAsyncClient client, String tableName) {
        List<AttributeDefinition> attributeDefinitions = new ArrayList<>();
        attributeDefinitions.add(AttributeDefinition.builder()
                .attributeName("Id")
                .attributeType("N")
                .build());

        List<KeySchemaElement> keySchema = new ArrayList<>();
        keySchema.add(KeySchemaElement.builder()
                .attributeName("Id")
                .keyType(KeyType.HASH) // Partition key
                .build());

        StreamSpecification streamSpecification = StreamSpecification.builder()
                .streamEnabled(true)
                .streamViewType(StreamViewType.NEW_IMAGE)
                .build();

        CreateTableRequest createTableRequest = CreateTableRequest.builder()
                .tableName(tableName)
                .attributeDefinitions(attributeDefinitions)
                .keySchema(keySchema)
                .billingMode(BillingMode.PAY_PER_REQUEST)
                .streamSpecification(streamSpecification)
                .build();

        try {
            System.out.println("Creating table " + tableName);
            CreateTableResponse result = client.createTable(createTableRequest).join();
            return result.tableDescription().latestStreamArn();
        } catch (Exception e) {
            if (e.getCause() instanceof ResourceInUseException) {
                System.out.println("Table already exists.");
                return describeTable(client, tableName).table().latestStreamArn();
            }
            throw e;
        }
    }

    public static DescribeTableResponse describeTable(DynamoDbAsyncClient client, String tableName) {
        return client.describeTable(DescribeTableRequest.builder()
                        .tableName(tableName)
                        .build())
                .join();
    }

    public static ScanResponse scanTable(DynamoDbAsyncClient dynamoDbClient, String tableName) {
        return dynamoDbClient.scan(ScanRequest.builder()
                        .tableName(tableName)
                        .build())
                .join();
    }

    public static void putItem(DynamoDbAsyncClient dynamoDbClient, String tableName, String id, String val) {
        Map<String, AttributeValue> item = new HashMap<>();
        item.put("Id", AttributeValue.builder().n(id).build());
        item.put("attribute-1", AttributeValue.builder().s(val).build());

        putItem(dynamoDbClient, tableName, item);
    }

    public static void putItem(DynamoDbAsyncClient dynamoDbClient, String tableName,
                               Map<String, AttributeValue> items) {
        PutItemRequest putItemRequest = PutItemRequest.builder()
                .tableName(tableName)
                .item(items)
                .build();
        dynamoDbClient.putItem(putItemRequest).join();
    }

    public static void updateItem(DynamoDbAsyncClient dynamoDbClient, String tableName, String id, String val) {
        Map<String, AttributeValue> key = new HashMap<>();
        key.put("Id", AttributeValue.builder().n(id).build());

        Map<String, String> expressionAttributeNames = new HashMap<>();
        expressionAttributeNames.put("#attr2", "attribute-2");

        Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
        expressionAttributeValues.put(":val", AttributeValue.builder().s(val).build());

        UpdateItemRequest updateItemRequest = UpdateItemRequest.builder()
                .tableName(tableName)
                .key(key)
                .updateExpression("SET #attr2 = :val")
                .expressionAttributeNames(expressionAttributeNames)
                .expressionAttributeValues(expressionAttributeValues)
                .build();

        dynamoDbClient.updateItem(updateItemRequest).join();
    }

    public static void deleteItem(DynamoDbAsyncClient dynamoDbClient, String tableName, String id) {
        Map<String, AttributeValue> key = new HashMap<>();
        key.put("Id", AttributeValue.builder().n(id).build());

        DeleteItemRequest deleteItemRequest = DeleteItemRequest.builder()
                .tableName(tableName)
                .key(key)
                .build();
        dynamoDbClient.deleteItem(deleteItemRequest).join();
    }
}
```

# API tingkat rendah DynamoDB Streams: Contoh Java
<a name="Streams.LowLevel.Walkthrough"></a>

**catatan**  
Kode di halaman ini tidak lengkap dan tidak menangani semua skenario untuk menggunakan Amazon DynamoDB Streams. Cara yang disarankan untuk menggunakan catatan aliran dari DynamoDB adalah melalui Adaptor Amazon Kinesis menggunakan Kinesis Client Library (KCL), seperti yang dijelaskan dalam [Menggunakan adaptor DynamoDB Streams Kinesis untuk memproses catatan aliran](Streams.KCLAdapter.md).

Bagian ini berisi program Java yang menunjukkan aksi DynamoDB Streams. Program ini melakukan hal berikut. Program ini melakukan hal berikut:

1. Membuat tabel DynamoDB dengan aliran diaktifkan.

1. Menjelaskan pengaturan aliran untuk tabel ini.

1. Memodifikasi data dalam tabel.

1. Menjelaskan pecahan di aliran.

1. Membaca catatan aliran dari serpihan.

1. Mengambil pecahan anak dan melanjutkan membaca catatan.

1. Membersihkan.

Saat Anda menjalankan program, Anda akan melihat output seperti berikut.

```
Testing Streams Demo
Creating an Amazon DynamoDB table TestTableForStreams with a simple primary key: Id
Waiting for TestTableForStreams to be created...
Current stream ARN for TestTableForStreams: arn:aws:dynamodb:us-east-2:123456789012:table/TestTableForStreams/stream/2018-03-20T16:49:55.208
Stream enabled: true
Update view type: NEW_AND_OLD_IMAGES

Performing write activities on TestTableForStreams
Processing item 1 of 100
Processing item 2 of 100
Processing item 3 of 100
...
Processing item 100 of 100
Shard: {ShardId: shardId-1234567890-...,SequenceNumberRange: {StartingSequenceNumber: 100002572486797508907,},}
    Shard iterator: EjYFEkX2a26eVTWe...
        StreamRecord(ApproximateCreationDateTime=2025-04-09T13:11:58Z, Keys={Id=AttributeValue(S=4)}, NewImage={Message=AttributeValue(S=New Item!), Id=AttributeValue(S=4)}, SequenceNumber=2000001584047545833909, SizeBytes=22, StreamViewType=NEW_AND_OLD_IMAGES)
        StreamRecord(ApproximateCreationDateTime=2025-04-09T13:11:58Z, Keys={Id=AttributeValue(S=4)}, NewImage={Message=AttributeValue(S=This is an updated item), Id=AttributeValue(S=4)}, OldImage={Message=AttributeValue(S=New Item!), Id=AttributeValue(S=4)}, SequenceNumber=2100003604869767892701, SizeBytes=55, StreamViewType=NEW_AND_OLD_IMAGES)
        StreamRecord(ApproximateCreationDateTime=2025-04-09T13:11:58Z, Keys={Id=AttributeValue(S=4)}, OldImage={Message=AttributeValue(S=This is an updated item), Id=AttributeValue(S=4)}, SequenceNumber=2200001099771112898434, SizeBytes=36, StreamViewType=NEW_AND_OLD_IMAGES)
...
Deleting the table...
Table StreamsDemoTable deleted.
Demo complete
```

**Example Contoh**  

```
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import software.amazon.awssdk.core.waiters.WaiterResponse;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeAction;
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.AttributeValueUpdate;
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.CreateTableResponse;
import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest;
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeStreamRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeStreamResponse;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.GetRecordsRequest;
import software.amazon.awssdk.services.dynamodb.model.GetRecordsResponse;
import software.amazon.awssdk.services.dynamodb.model.GetShardIteratorRequest;
import software.amazon.awssdk.services.dynamodb.model.GetShardIteratorResponse;
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
import software.amazon.awssdk.services.dynamodb.model.KeyType;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.Record;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
import software.amazon.awssdk.services.dynamodb.model.Shard;
import software.amazon.awssdk.services.dynamodb.model.ShardFilter;
import software.amazon.awssdk.services.dynamodb.model.ShardFilterType;
import software.amazon.awssdk.services.dynamodb.model.ShardIteratorType;
import software.amazon.awssdk.services.dynamodb.model.StreamSpecification;
import software.amazon.awssdk.services.dynamodb.model.TableDescription;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
import software.amazon.awssdk.services.dynamodb.streams.DynamoDbStreamsClient;
import software.amazon.awssdk.services.dynamodb.waiters.DynamoDbWaiter;

public class StreamsLowLevelDemo {


    public static void main(String[] args) {
        final String usage = "Testing Streams Demo";
        try {
            System.out.println(usage);

            String tableName = "StreamsDemoTable";
            String key = "Id";
            System.out.println("Creating an Amazon DynamoDB table " + tableName + " with a simple primary key: " + key);
            Region region = Region.US_WEST_2;
            DynamoDbClient ddb = DynamoDbClient.builder()
                    .region(region)
                    .build();

            DynamoDbStreamsClient ddbStreams = DynamoDbStreamsClient.builder()
                    .region(region)
                    .build();
            DescribeTableRequest describeTableRequest = DescribeTableRequest.builder()
                    .tableName(tableName)
                    .build();
            TableDescription tableDescription = null;
            try{
                tableDescription = ddb.describeTable(describeTableRequest).table();
            }catch (Exception e){
                System.out.println("Table " + tableName + " does not exist.");
                tableDescription = createTable(ddb, tableName, key);
            }

            // Print the stream settings for the table
            String streamArn = tableDescription.latestStreamArn();
           
            StreamSpecification streamSpec = tableDescription.streamSpecification();
            System.out.println("Current stream ARN for " + tableDescription.tableName() + ": " +
                   streamArn);
            System.out.println("Stream enabled: " + streamSpec.streamEnabled());
            System.out.println("Update view type: " + streamSpec.streamViewType());
            System.out.println();
            // Generate write activity in the table
            System.out.println("Performing write activities on " + tableName);
            int maxItemCount = 100;
            for (Integer i = 1; i <= maxItemCount; i++) {
                System.out.println("Processing item " + i + " of " + maxItemCount);
                // Write a new item
                putItemInTable(key, i, tableName, ddb);
                // Update the item
                updateItemInTable(key, i, tableName, ddb);
                // Delete the item
                deleteDynamoDBItem(key, i, tableName, ddb);
            }

            // Process Stream
            processStream(streamArn, maxItemCount, ddb, ddbStreams, tableName);

            // Delete the table
            System.out.println("Deleting the table...");
            DeleteTableRequest deleteTableRequest = DeleteTableRequest.builder()
                    .tableName(tableName)
                    .build();
            ddb.deleteTable(deleteTableRequest);
            System.out.println("Table " + tableName + " deleted.");
            System.out.println("Demo complete");
            ddb.close();
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }

    private static void processStream(String streamArn, int maxItemCount, DynamoDbClient ddb, DynamoDbStreamsClient ddbStreams, String tableName) {
        // Get all the shard IDs from the stream. Note that DescribeStream returns
        // the shard IDs one page at a time.
        String lastEvaluatedShardId = null;
        do {
            DescribeStreamRequest describeStreamRequest = DescribeStreamRequest.builder()
                    .streamArn(streamArn)
                    .exclusiveStartShardId(lastEvaluatedShardId).build();
            DescribeStreamResponse describeStreamResponse = ddbStreams.describeStream(describeStreamRequest);

            List<Shard> shards = describeStreamResponse.streamDescription().shards();

            // Process each shard on this page

            fetchShardsAndReadRecords(streamArn, maxItemCount, ddbStreams, shards);

            // If LastEvaluatedShardId is set, then there is
            // at least one more page of shard IDs to retrieve
            lastEvaluatedShardId = describeStreamResponse.streamDescription().lastEvaluatedShardId();

        } while (lastEvaluatedShardId != null);

    }

    private static void fetchShardsAndReadRecords(String streamArn, int maxItemCount, DynamoDbStreamsClient ddbStreams, List<Shard> shards) {
        for (Shard shard : shards) {
            String shardId = shard.shardId();
            System.out.println("Shard: " + shard);

            // Get an iterator for the current shard
            GetShardIteratorRequest shardIteratorRequest = GetShardIteratorRequest.builder()
                    .streamArn(streamArn).shardId(shardId)
                    .shardIteratorType(ShardIteratorType.TRIM_HORIZON).build();

            GetShardIteratorResponse getShardIteratorResult = ddbStreams.getShardIterator(shardIteratorRequest);

            String currentShardIter = getShardIteratorResult.shardIterator();

            // Shard iterator is not null until the Shard is sealed (marked as READ_ONLY).
            // To prevent running the loop until the Shard is sealed, we process only the
            // items that were written into DynamoDB and then exit.
            int processedRecordCount = 0;
            while (currentShardIter != null && processedRecordCount < maxItemCount) {
                // Use the shard iterator to read the stream records
                GetRecordsRequest getRecordsRequest = GetRecordsRequest.builder()
                        .shardIterator(currentShardIter).build();
                GetRecordsResponse getRecordsResult = ddbStreams.getRecords(getRecordsRequest);
                List<Record> records = getRecordsResult.records();
                for (Record record : records) {
                    System.out.println("        " + record.dynamodb());
                }
                processedRecordCount += records.size();
                currentShardIter = getRecordsResult.nextShardIterator();
            }
            if (currentShardIter == null){
                System.out.println("Shard has been fully processed. Shard iterator is null.");
                System.out.println("Fetch the child shard to continue processing instead of bulk fetching all shards");
                DescribeStreamRequest describeStreamRequestForChildShards = DescribeStreamRequest.builder()
                        .streamArn(streamArn)
                        .shardFilter(ShardFilter.builder()
                                .type(ShardFilterType.CHILD_SHARDS)
                                .shardId(shardId).build())
                        .build();
                DescribeStreamResponse describeStreamResponseChildShards = ddbStreams.describeStream(describeStreamRequestForChildShards);
                fetchShardsAndReadRecords(streamArn, maxItemCount, ddbStreams, describeStreamResponseChildShards.streamDescription().shards());
            }
        }
    }

    private static void putItemInTable(String key, Integer i, String tableName, DynamoDbClient ddb) {
        Map<String, AttributeValue> item = new HashMap<>();
        item.put(key, AttributeValue.builder()
                .s(i.toString())
                .build());
        item.put("Message", AttributeValue.builder()
                .s("New Item!")
                .build());
        PutItemRequest request = PutItemRequest.builder()
                .tableName(tableName)
                .item(item)
                .build();
        ddb.putItem(request);
    }

    private static void updateItemInTable(String key, Integer i, String tableName, DynamoDbClient ddb) {

        HashMap<String, AttributeValue> itemKey = new HashMap<>();
        itemKey.put(key, AttributeValue.builder()
                .s(i.toString())
                .build());


        HashMap<String, AttributeValueUpdate> updatedValues = new HashMap<>();
        updatedValues.put("Message", AttributeValueUpdate.builder()
                .value(AttributeValue.builder().s("This is an updated item").build())
                .action(AttributeAction.PUT)
                .build());

        UpdateItemRequest request = UpdateItemRequest.builder()
                .tableName(tableName)
                .key(itemKey)
                .attributeUpdates(updatedValues)
                .build();
        ddb.updateItem(request);
    }

    public static void deleteDynamoDBItem(String key, Integer i, String tableName, DynamoDbClient ddb) {
        HashMap<String, AttributeValue> keyToGet = new HashMap<>();
        keyToGet.put(key, AttributeValue.builder()
                .s(i.toString())
                .build());

        DeleteItemRequest deleteReq = DeleteItemRequest.builder()
                .tableName(tableName)
                .key(keyToGet)
                .build();
        ddb.deleteItem(deleteReq);
    }

    public static TableDescription createTable(DynamoDbClient ddb, String tableName, String key) {
        DynamoDbWaiter dbWaiter = ddb.waiter();
        StreamSpecification streamSpecification = StreamSpecification.builder()
                .streamEnabled(true)
                .streamViewType("NEW_AND_OLD_IMAGES")
                .build();
        CreateTableRequest request = CreateTableRequest.builder()
                .attributeDefinitions(AttributeDefinition.builder()
                        .attributeName(key)
                        .attributeType(ScalarAttributeType.S)
                        .build())
                .keySchema(KeySchemaElement.builder()
                        .attributeName(key)
                        .keyType(KeyType.HASH)
                        .build())
                .billingMode(BillingMode.PAY_PER_REQUEST) //  DynamoDB automatically scales based on traffic.
                .tableName(tableName)
                .streamSpecification(streamSpecification)
                .build();

        TableDescription newTable;
        try {
            CreateTableResponse response = ddb.createTable(request);
            DescribeTableRequest tableRequest = DescribeTableRequest.builder()
                    .tableName(tableName)
                    .build();
                    
            System.out.println("Waiting for " + tableName + " to be created...");

            // Wait until the Amazon DynamoDB table is created.
            WaiterResponse<DescribeTableResponse> waiterResponse = dbWaiter.waitUntilTableExists(tableRequest);
            waiterResponse.matched().response().ifPresent(System.out::println);
            newTable = response.tableDescription();
            return newTable;

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
        return null;
    }



}
```

# DynamoDB Streams dan pemicu AWS Lambda
<a name="Streams.Lambda"></a>

Amazon DynamoDB terintegrasi AWS Lambda sehingga Anda dapat *membuat* pemicu —potongan kode yang secara otomatis merespons peristiwa di DynamoDB Streams. Dengan pemicu, Anda dapat membangun aplikasi yang bereaksi terhadap modifikasi data di tabel DynamoDB.

**Topics**
+ [Tutorial \$11: Menggunakan filter untuk memproses semua peristiwa dengan Amazon AWS Lambda DynamoDB dan menggunakan AWS CLI](Streams.Lambda.Tutorial.md)
+ [Tutorial \$12: Menggunakan filter untuk memproses beberapa peristiwa dengan DynamoDB dan Lambda](Streams.Lambda.Tutorial2.md)
+ [Praktik terbaik menggunakan DynamoDB Streams dengan Lambda](Streams.Lambda.BestPracticesWithDynamoDB.md)

Jika Anda mengaktifkan DynamoDB Streams pada tabel, Anda dapat mengaitkan aliran Amazon Resource Name (ARN) dengan fungsi yang Anda tulis. AWS Lambda Semua tindakan mutasi pada tabel DynamoDB tersebut kemudian dapat ditangkap sebagai item di aliran. Misalnya, Anda dapat menyetel pemicu sehingga ketika item dalam tabel diubah, rekaman baru segera muncul di aliran tabel tersebut. 

**catatan**  
Jika Anda berlangganan lebih dari dua fungsi Lambda ke satu aliran DynamoDB, pelambatan baca mungkin terjadi.

Layanan [AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html) ini melakukan polling aliran untuk catatan baru empat kali per detik. Ketika rekaman aliran baru tersedia, fungsi Lambda Anda dipanggil secara sinkron. Anda dapat berlangganan hingga dua fungsi Lambda ke aliran DynamoDB yang sama. Jika Anda berlangganan lebih dari dua fungsi Lambda ke aliran DynamoDB yang sama, pelambatan baca mungkin terjadi.

Fungsi Lambda dapat mengirimkan pemberitahuan, memulai alur kerja, atau melakukan banyak tindakan lain yang Anda tentukan. Anda dapat menulis fungsi Lambda dengan mudah menyalin setiap catatan aliran ke penyimpanan persisten, seperti Amazon S3 File Gateway (Amazon S3), dan membuat jejak audit permanen dari aktivitas penulisan di tabel Anda. Selain itu, misalkan Anda mempunyai aplikasi game seluler yang menulis ke tabel `GameScores`. Setiap kali atribut `TopScore` dari tabel `GameScores` diperbarui, catatan stream yang sesuai ditulis ke stream tabel ini. Peristiwa ini kemudian dapat memicu fungsi Lambda yang memposting pesan ucapan selamat di jaringan media sosial. Fungsi ini juga dapat ditulis untuk mengabaikan catatan stream yang tidak memperbarui `GameScores`, atau yang tidak memodifikasi atribut `TopScore`.

Jika fungsi Anda mengembalikan kesalahan, Lambda akan mencoba ulang batch tersebut hingga berhasil diproses atau datanya habis masa berlakunya. Anda juga dapat mengonfigurasi Lambda untuk mencoba ulang dengan batch yang lebih kecil, membatasi jumlah percobaan ulang, membuang catatan setelah terlalu lama, dan opsi lainnya.

Sebagai praktik terbaik kinerja, fungsi Lambda harus berumur pendek. Untuk menghindari penundaan pemrosesan yang tidak perlu, logika yang rumit juga tidak boleh dijalankan. Khususnya untuk aliran kecepatan tinggi, lebih baik memicu alur kerja fungsi langkah pasca-pemrosesan asinkron daripada Lambdas yang berjalan lama secara sinkron.

 Anda dapat menggunakan pemicu Lambda di berbagai AWS akun dengan mengonfigurasi kebijakan berbasis sumber daya pada aliran DynamoDB untuk memberikan akses baca lintas akun ke fungsi Lambda. Untuk mempelajari lebih lanjut tentang cara mengonfigurasi streaming agar memungkinkan akses lintas akun, lihat [Berbagi akses dengan fungsi AWS Lambda lintas akun di](rbac-cross-account-access.md#shared-access-cross-acount-lambda) Panduan Pengembang DynamoDB.

Untuk informasi selengkapnya AWS Lambda, lihat [Panduan AWS Lambda Pengembang](https://docs.aws.amazon.com/lambda/latest/dg/).

# Tutorial \$11: Menggunakan filter untuk memproses semua peristiwa dengan Amazon AWS Lambda DynamoDB dan menggunakan AWS CLI
<a name="Streams.Lambda.Tutorial"></a>

 

Dalam tutorial ini, Anda akan membuat AWS Lambda pemicu untuk memproses aliran dari tabel DynamoDB.

**Topics**
+ [Langkah 1: Buat tabel DynamoDB dengan aliran diaktifkan](#Streams.Lambda.Tutorial.CreateTable)
+ [Langkah 2: Buat peran eksekusi Lambda](#Streams.Lambda.Tutorial.CreateRole)
+ [Langkah 3: Buat Topik Amazon SNS](#Streams.Lambda.Tutorial.SNSTopic)
+ [Langkah 4: Buat dan uji fungsi Lambda](#Streams.Lambda.Tutorial.LambdaFunction)
+ [Langkah 5: Buat dan uji pemicu](#Streams.Lambda.Tutorial.CreateTrigger)

Skenario untuk tutorial ini adalah Woofer, sebuah jejaring sosial sederhana. Pengguna Woofer berkomunikasi menggunakan *bark* (pesan teks singkat) yang dikirim ke pengguna Woofer lainnya. Diagram berikut menunjukkan komponen dan alur kerja untuk aplikasi ini.

![\[Alur kerja aplikasi Woofer dari tabel DynamoDB, catatan aliran, fungsi Lambda, dan topik Amazon SNS.\]](http://docs.aws.amazon.com/id_id/amazondynamodb/latest/developerguide/images/StreamsAndTriggers.png)


1. Seorang pengguna menulis item ke tabel DynamoDB (`BarkTable`). Setiap item dalam tabel mewakili bark.

1. Sebuah catatan stream baru ditulis untuk mencerminkan bahwa item baru telah ditambahkan ke `BarkTable`.

1. Rekaman aliran baru memicu AWS Lambda fungsi (`publishNewBark`).

1. Jika catatan stream menunjukkan bahwa item baru ditambahkan ke `BarkTable`, fungsi Lambda membaca data dari catatan stream dan menerbitkan pesan ke topik di Amazon Simple Notification Service (Amazon SNS).

1. Pesan diterima oleh pelanggan untuk topik Amazon SNS. (Dalam tutorial ini, satu-satunya pelanggan adalah alamat email.)

**Sebelum Anda Memulai**  
Tutorial ini menggunakan AWS Command Line Interface AWS CLI. Jika Anda belum melakukannya, ikuti petunjuk di [Panduan Pengguna AWS Command Line Interface](https://docs.aws.amazon.com/cli/latest/userguide/) untuk menginstal dan mengkonfigurasi AWS CLI.

## Langkah 1: Buat tabel DynamoDB dengan aliran diaktifkan
<a name="Streams.Lambda.Tutorial.CreateTable"></a>

Pada langkah ini, Anda membuat tabel DynamoDB (`BarkTable`) untuk menyimpan semua bark dari pengguna Woofer. Kunci primer terdiri dari `Username` (kunci partisi) dan `Timestamp` (kunci urutan). Kedua atribut ini berjenis string.

`BarkTable` memiliki aliran yang diaktifkan. Kemudian dalam tutorial ini, Anda membuat pemicu dengan mengaitkan AWS Lambda fungsi dengan aliran.

1. Masukkan perintah berikut untuk membuat tabel.

   ```
   aws dynamodb create-table \
       --table-name BarkTable \
       --attribute-definitions AttributeName=Username,AttributeType=S AttributeName=Timestamp,AttributeType=S \
       --key-schema AttributeName=Username,KeyType=HASH  AttributeName=Timestamp,KeyType=RANGE \
       --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
       --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES
   ```

1. Dalam output, cari `LatestStreamArn`.

   ```
   ...
   "LatestStreamArn": "arn:aws:dynamodb:region:accountID:table/BarkTable/stream/timestamp
   ...
   ```

   Buat catatan tentang `region` dan `accountID`, karena Anda membutuhkannya untuk langkah-langkah lain dalam tutorial ini.

## Langkah 2: Buat peran eksekusi Lambda
<a name="Streams.Lambda.Tutorial.CreateRole"></a>

Pada langkah ini, Anda membuat peran AWS Identity and Access Management (IAM) (`WooferLambdaRole`) dan menetapkan izin untuk itu. Peran ini digunakan oleh fungsi Lambda yang Anda buat di [Langkah 4: Buat dan uji fungsi Lambda](#Streams.Lambda.Tutorial.LambdaFunction). 

Anda juga membuat kebijakan untuk peran. Kebijakan ini berisi semua izin yang dibutuhkan fungsi Lambda pada saat waktu aktif.

1. Buat file bernama `trust-relationship.json` dengan isi berikut ini.

------
#### [ JSON ]

****  

   ```
   {
      "Version":"2012-10-17",		 	 	 
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "lambda.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
        }
      ]
    }
   ```

------

1. Masukkan perintah berikut untuk membuat `WooferLambdaRole`.

   ```
   aws iam create-role --role-name WooferLambdaRole \
       --path "/service-role/" \
       --assume-role-policy-document file://trust-relationship.json
   ```

1. Buat file bernama `role-policy.json` dengan isi berikut ini. (Ganti `region` dan `accountID` dengan AWS Wilayah dan ID akun Anda.)

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "logs:CreateLogGroup",
                   "logs:CreateLogStream",
                   "logs:PutLogEvents"
               ],
               "Resource": "arn:aws:logs:us-east-1:111122223333:*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "dynamodb:DescribeStream",
                   "dynamodb:GetRecords",
                   "dynamodb:GetShardIterator",
                   "dynamodb:ListStreams"
               ],
               "Resource": "arn:aws:dynamodb:us-east-1:111122223333:table/BarkTable/stream/*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "sns:Publish"
               ],
               "Resource": [
                   "*"
               ]
           }
       ]
   }
   ```

------

   Kebijakan ini memiliki empat pernyataan yang memungkinkan `WooferLambdaRole` untuk melakukan hal berikut:
   + Menjalankan fungsi Lambda (`publishNewBark`). Anda membuat fungsi nanti dalam tutorial ini.
   + Akses CloudWatch Log Amazon. Fungsi Lambda menulis diagnostik ke CloudWatch Log saat runtime.
   + Membaca data dari stream DynamoDB untuk `BarkTable`.
   + Memublikasikan pesan ke Amazon SNS.

1. Masukkan perintah berikut untuk melampirkan kebijakan ke `WooferLambdaRole`.

   ```
   aws iam put-role-policy --role-name WooferLambdaRole \
       --policy-name WooferLambdaRolePolicy \
       --policy-document file://role-policy.json
   ```

## Langkah 3: Buat Topik Amazon SNS
<a name="Streams.Lambda.Tutorial.SNSTopic"></a>

Pada langkah ini, Anda membuat topik Amazon SNS (`wooferTopic`) dan mendaftarkan langganan alamat email untuk itu. Fungsi Lambda Anda menggunakan topik ini untuk memublikasikan bark baru dari pengguna Woofer.

1. Masukkan perintah berikut untuk membuat topik Amazon SNS.

   ```
   aws sns create-topic --name wooferTopic
   ```

1. Masukkan perintah berikut untuk mendaftarkan langganan alamat email ke `wooferTopic`. (Ganti `region` dan `accountID` dengan Wilayah AWS dan ID akun Anda, dan ganti `example@example.com` dengan alamat email yang valid.)

   ```
   aws sns subscribe \
       --topic-arn arn:aws:sns:region:accountID:wooferTopic \
       --protocol email \
       --notification-endpoint example@example.com
   ```

1. Amazon SNS mengirimkan pesan konfirmasi ke alamat email Anda. Pilih tautan **Konfirmasi langganan** di pesan tersebut untuk menyelesaikan proses berlangganan.

## Langkah 4: Buat dan uji fungsi Lambda
<a name="Streams.Lambda.Tutorial.LambdaFunction"></a>

Pada langkah ini, Anda membuat AWS Lambda fungsi (`publishNewBark`) untuk memproses catatan aliran dari`BarkTable`.

Fungsi `publishNewBark` hanya memproses hanya peristiwa stream yang sesuai dengan item baru di `BarkTable`. Fungsi membaca data dari peristiwa tersebut, dan kemudian memanggil Amazon SNS untuk memublikasikannya.

1. Buat file bernama `publishNewBark.js` dengan isi berikut ini. Ganti `region` dan `accountID` dengan AWS Wilayah dan ID akun Anda.

   ```
   'use strict';
   var AWS = require("aws-sdk");
   var sns = new AWS.SNS();
   
   exports.handler = (event, context, callback) => {
   
       event.Records.forEach((record) => {
           console.log('Stream record: ', JSON.stringify(record, null, 2));
   
           if (record.eventName == 'INSERT') {
               var who = JSON.stringify(record.dynamodb.NewImage.Username.S);
               var when = JSON.stringify(record.dynamodb.NewImage.Timestamp.S);
               var what = JSON.stringify(record.dynamodb.NewImage.Message.S);
               var params = {
                   Subject: 'A new bark from ' + who,
                   Message: 'Woofer user ' + who + ' barked the following at ' + when + ':\n\n ' + what,
                   TopicArn: 'arn:aws:sns:region:accountID:wooferTopic'
               };
               sns.publish(params, function(err, data) {
                   if (err) {
                       console.error("Unable to send message. Error JSON:", JSON.stringify(err, null, 2));
                   } else {
                       console.log("Results from sending message: ", JSON.stringify(data, null, 2));
                   }
               });
           }
       });
       callback(null, `Successfully processed ${event.Records.length} records.`);
   };
   ```

1. Buat file zip untuk menampung `publishNewBark.js`. Jika Anda memiliki utilitas baris perintah zip, Anda dapat memasukkan perintah berikut untuk melakukan hal ini.

   ```
   zip publishNewBark.zip publishNewBark.js
   ```

1. Ketika Anda membuat fungsi Lambda, Anda menentukan Amazon Resource Name (ARN) untuk `WooferLambdaRole`, yang Anda buat di [Langkah 2: Buat peran eksekusi Lambda](#Streams.Lambda.Tutorial.CreateRole). Masukkan perintah berikut untuk mengambil ARN ini.

   ```
   aws iam get-role --role-name WooferLambdaRole
   ```

   Dalam output, cari ARN untuk `WooferLambdaRole`.

   ```
   ...
   "Arn": "arn:aws:iam::region:role/service-role/WooferLambdaRole"
   ...
   ```

   Masukkan perintah berikut untuk membuat fungsi Lambda. Ganti *roleARN* dengan ARN untuk. `WooferLambdaRole`

   ```
   aws lambda create-function \
       --region region \
       --function-name publishNewBark \
       --zip-file fileb://publishNewBark.zip \
       --role roleARN \
       --handler publishNewBark.handler \
       --timeout 5 \
       --runtime nodejs16.x
   ```

1. Sekarang uji `publishNewBark` untuk memverifikasi bahwa ia bekerja. Untuk melakukannya, Anda memberikan input yang menyerupai catatan nyata dari DynamoDB Streams.

   Buat file bernama `payload.json` dengan isi berikut ini. Ganti `region` dan `accountID` dengan ID akun Wilayah AWS dan Anda.

   ```
   {
       "Records": [
           {
               "eventID": "7de3041dd709b024af6f29e4fa13d34c",
               "eventName": "INSERT",
               "eventVersion": "1.1",
               "eventSource": "aws:dynamodb",
               "awsRegion": "region",
               "dynamodb": {
                   "ApproximateCreationDateTime": 1479499740,
                   "Keys": {
                       "Timestamp": {
                           "S": "2016-11-18:12:09:36"
                       },
                       "Username": {
                           "S": "John Doe"
                       }
                   },
                   "NewImage": {
                       "Timestamp": {
                           "S": "2016-11-18:12:09:36"
                       },
                       "Message": {
                           "S": "This is a bark from the Woofer social network"
                       },
                       "Username": {
                           "S": "John Doe"
                       }
                   },
                   "SequenceNumber": "13021600000000001596893679",
                   "SizeBytes": 112,
                   "StreamViewType": "NEW_IMAGE"
               },
               "eventSourceARN": "arn:aws:dynamodb:region:account ID:table/BarkTable/stream/2016-11-16T20:42:48.104"
           }
       ]
   }
   ```

   Masukkan perintah berikut untuk menguji fungsi `publishNewBark`.

   ```
   aws lambda invoke --function-name publishNewBark --payload file://payload.json --cli-binary-format raw-in-base64-out output.txt
   ```

   Jika tes berhasil, Anda akan melihat output sebagai berikut.

   ```
   {
       "StatusCode": 200,
       "ExecutedVersion": "$LATEST"
   }
   ```

   Selain itu, file `output.txt` akan berisi teks berikut.

   ```
   "Successfully processed 1 records."
   ```

   Anda juga akan menerima pesan email baru dalam beberapa menit.
**catatan**  
AWS Lambda menulis informasi diagnostik ke Amazon CloudWatch Logs. Jika Anda mengalami kesalahan dengan fungsi Lambda Anda, Anda dapat menggunakan diagnostik ini untuk tujuan pemecahan masalah:  
Buka CloudWatch konsol di [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).
Pilih **Log** di panel navigasi.
Pilih grup log berikut ini: `/aws/lambda/publishNewBark`
Pilih stream log terbaru untuk melihat output (dan kesalahan) dari fungsi.

## Langkah 5: Buat dan uji pemicu
<a name="Streams.Lambda.Tutorial.CreateTrigger"></a>

Dalam [Langkah 4: Buat dan uji fungsi Lambda](#Streams.Lambda.Tutorial.LambdaFunction), Anda menguji fungsi Lambda untuk memastikan bahwa itu berjalan dengan benar. Pada langkah ini, Anda membuat *pemicu* dengan mengaitkan fungsi Lambda (`publishNewBark`) dengan sumber peristiwa (aliran `BarkTable`).

1. Saat Anda membuat pemicu, Anda perlu menentukan ARN untuk stream `BarkTable`. Masukkan perintah berikut untuk mengambil ARN ini.

   ```
   aws dynamodb describe-table --table-name BarkTable
   ```

   Dalam output, cari `LatestStreamArn`.

   ```
   ...
    "LatestStreamArn": "arn:aws:dynamodb:region:accountID:table/BarkTable/stream/timestamp
   ...
   ```

1. Masukkan perintah berikut untuk membuat pemicu. Ganti `streamARN` dengan ARN stream yang sebenarnya.

   ```
   aws lambda create-event-source-mapping \
       --region region \
       --function-name publishNewBark \
       --event-source streamARN  \
       --batch-size 1 \
       --starting-position TRIM_HORIZON
   ```

1. Uji pemicu. Masukkan perintah berikut untuk menambahkan item ke `BarkTable`.

   ```
   aws dynamodb put-item \
       --table-name BarkTable \
       --item Username={S="Jane Doe"},Timestamp={S="2016-11-18:14:32:17"},Message={S="Testing...1...2...3"}
   ```

   Anda akan menerima pesan email baru dalam beberapa menit.

1. Buka konsol DynamoDB dan tambahkan beberapa item lagi ke `BarkTable`. Anda harus menentukan nilai untuk atribut `Username` dan `Timestamp`. (Anda juga harus menentukan nilai untuk `Message`, meskipun tidak diperlukan.) Anda akan menerima pesan email baru untuk setiap item yang ditambahkan ke `BarkTable`.

   Fungsi Lambda memproses hanya item baru yang Anda tambahkan ke `BarkTable`. Jika Anda memperbarui atau menghapus item dalam tabel, fungsi tidak melakukan apa pun.

**catatan**  
AWS Lambda menulis informasi diagnostik ke Amazon CloudWatch Logs. Jika Anda mengalami kesalahan dengan fungsi Lambda Anda, Anda dapat menggunakan diagnostik ini untuk tujuan pemecahan masalah.  
Buka CloudWatch konsol di [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).
Pilih **Log** di panel navigasi.
Pilih grup log berikut ini: `/aws/lambda/publishNewBark`
Pilih stream log terbaru untuk melihat output (dan kesalahan) dari fungsi.

# Tutorial \$12: Menggunakan filter untuk memproses beberapa peristiwa dengan DynamoDB dan Lambda
<a name="Streams.Lambda.Tutorial2"></a>

Dalam tutorial ini, Anda akan membuat AWS Lambda pemicu untuk memproses hanya beberapa peristiwa dalam aliran dari tabel DynamoDB.

**Topics**
+ [Menyatukan semuanya - CloudFormation](#Streams.Lambda.Tutorial2.Cloudformation)
+ [Menyatukan semuanya - CDK](#Streams.Lambda.Tutorial2.CDK)

Dengan [pemfilteran peristiwa Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html), Anda dapat menggunakan ekspresi filter untuk mengontrol peristiwa mana yang dikirim Lambda ke fungsi Anda untuk diproses. Anda dapat mengonfigurasi hingga 5 filter berbeda per aliran DynamoDB. Jika Anda menggunakan jendela batching, Lambda menerapkan kriteria filter untuk setiap acara baru untuk melihat apakah itu harus disertakan dalam batch saat ini.

Filter diterapkan melalui struktur yang disebut `FilterCriteria`. 3 atribut utama `FilterCriteria` adalah`metadata properties`, `data properties`, dan `filter patterns`. 

Berikut adalah contoh struktur dari acara DynamoDB Streams:

```
{
  "eventID": "c9fbe7d0261a5163fcb6940593e41797",
  "eventName": "INSERT",
  "eventVersion": "1.1",
  "eventSource": "aws:dynamodb",
  "awsRegion": "us-east-2",
  "dynamodb": {
    "ApproximateCreationDateTime": 1664559083.0,
    "Keys": {
      "SK": { "S": "PRODUCT#CHOCOLATE#DARK#1000" },
      "PK": { "S": "COMPANY#1000" }
    },
    "NewImage": {
      "quantity": { "N": "50" },
      "company_id": { "S": "1000" },
      "fabric": { "S": "Florida Chocolates" },
      "price": { "N": "15" },
      "stores": { "N": "5" },
      "product_id": { "S": "1000" },
      "SK": { "S": "PRODUCT#CHOCOLATE#DARK#1000" },
      "PK": { "S": "COMPANY#1000" },
      "state": { "S": "FL" },
      "type": { "S": "" }
    },
    "SequenceNumber": "700000000000888747038",
    "SizeBytes": 174,
    "StreamViewType": "NEW_AND_OLD_IMAGES"
  },
  "eventSourceARN": "arn:aws:dynamodb:us-east-2:111122223333:table/chocolate-table-StreamsSampleDDBTable-LUOI6UXQY7J1/stream/2022-09-30T17:05:53.209"
}
```

`metadata properties` adalah bidang objek peristiwa. Dalam kasus DynamoDB Streams, `metadata properties` adalah bidang seperti `dynamodb` atau `eventName`. 

`data properties` adalah bidang badan peristiwa. Untuk memfilter `data properties`, pastikan untuk memasukkannya ke `FilterCriteria` dalam kunci yang tepat. Untuk sumber peristiwa DynamoDB, kunci data adalah `NewImage` atau `OldImage`.

Akhirnya, aturan filter akan menentukan ekspresi filter yang ingin Anda terapkan ke properti tertentu. Berikut ini adalah beberapa contohnya:


| Operator perbandingan | Contoh | Sintaks aturan (Sebagian) | 
| --- | --- | --- | 
|  Null  |  Jenis Produk adalah null  |  `{ "product_type": { "S": null } } `  | 
|  Kosong  |  Nama produk kosong  |  `{ "product_name": { "S": [ ""] } } `  | 
|  Sama dengan  |  Negara bagian sama dengan Florida  |  `{ "state": { "S": ["FL"] } } `  | 
|  Dan  |  Negara bagian produk sama dengan Florida dan kategori produk Cokelat  |  `{ "state": { "S": ["FL"] } , "category": { "S": [ "CHOCOLATE"] } } `  | 
|  Atau  |  Negara bagian produk adalah Florida atau California  |  `{ "state": { "S": ["FL","CA"] } } `  | 
|  Bukan  |  Negara bagian produk bukan Florida  |  `{"state": {"S": [{"anything-but": ["FL"]}]}}`  | 
|  Exists  |  Produk Rumahan ada  |  `{"homemade": {"S": [{"exists": true}]}}`  | 
|  Tidak ada  |  Produk Rumahan tidak ada  |  `{"homemade": {"S": [{"exists": false}]}}`  | 
|  Dimulai dengan  |  PK dimulai dengan PERUSAHAAN  |  `{"PK": {"S": [{"prefix": "COMPANY"}]}}`  | 

Anda dapat menentukan hingga 5 pola penyaringan peristiwa untuk fungsi Lambda. Perhatikan bahwa masing-masing dari 5 peristiwa tersebut akan dievaluasi sebagai OR logis. Jadi jika Anda mengkonfigurasi dua filter bernama `Filter_One` dan`Filter_Two`, fungsi Lambda akan mengeksekusi `Filter_One` OR `Filter_Two`.

**catatan**  
Di halaman [pemfilteran acara Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html) ada beberapa opsi untuk memfilter dan membandingkan nilai numerik, namun dalam kasus peristiwa filter DynamoDB itu tidak berlaku karena angka di DynamoDB disimpan sebagai string. Misalnya ` "quantity": { "N": "50" }`, kita tahu itu nomor karena properti `"N"`.

## Menyatukan semuanya - CloudFormation
<a name="Streams.Lambda.Tutorial2.Cloudformation"></a>

Untuk menampilkan fungsionalitas pemfilteran acara dalam praktiknya, berikut adalah contoh CloudFormation template. Templat ini akan menghasilkan tabel DynamoDB Sederhana dengan PK Kunci Partisi dan SK Kunci Urutan dengan Amazon DynamoDB Streams diaktifkan. Ini akan membuat fungsi lambda dan peran Eksekusi Lambda sederhana yang memungkinkan penulisan log ke Amazon Cloudwatch, dan membaca peristiwa dari Amazon DynamoDB Stream. Ini juga akan menambahkan pemetaan sumber peristiwa antara DynamoDB Streams dan fungsi Lambda, sehingga fungsi tersebut dapat dijalankan setiap kali ada kejadian di Amazon DynamoDB Stream.

```
AWSTemplateFormatVersion: "2010-09-09"

Description: Sample application that presents AWS Lambda event source filtering 
with Amazon DynamoDB Streams.

Resources:
  StreamsSampleDDBTable:
    Type: AWS::DynamoDB::Table
    Properties:
      AttributeDefinitions:
        - AttributeName: "PK"
          AttributeType: "S"
        - AttributeName: "SK"
          AttributeType: "S"
      KeySchema:
        - AttributeName: "PK"
          KeyType: "HASH"
        - AttributeName: "SK"
          KeyType: "RANGE"
      StreamSpecification:
        StreamViewType: "NEW_AND_OLD_IMAGES"
      ProvisionedThroughput:
        ReadCapacityUnits: 5
        WriteCapacityUnits: 5

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17",		 	 	 
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: "/"
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: "2012-10-17",		 	 	 
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: arn:aws:logs:*:*:*
              - Effect: Allow
                Action:
                  - dynamodb:DescribeStream
                  - dynamodb:GetRecords
                  - dynamodb:GetShardIterator
                  - dynamodb:ListStreams
                Resource: !GetAtt StreamsSampleDDBTable.StreamArn

  EventSourceDDBTableStream:
    Type: AWS::Lambda::EventSourceMapping
    Properties:
      BatchSize: 1
      Enabled: True
      EventSourceArn: !GetAtt StreamsSampleDDBTable.StreamArn
      FunctionName: !GetAtt ProcessEventLambda.Arn
      StartingPosition: LATEST

  ProcessEventLambda:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.7
      Timeout: 300
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: |
          import logging

          LOGGER = logging.getLogger()
          LOGGER.setLevel(logging.INFO)

          def handler(event, context):
            LOGGER.info('Received Event: %s', event)
            for rec in event['Records']:
              LOGGER.info('Record: %s', rec)

Outputs:
  StreamsSampleDDBTable:
    Description: DynamoDB Table ARN created for this example
    Value: !GetAtt StreamsSampleDDBTable.Arn
  StreamARN:
    Description: DynamoDB Table ARN created for this example
    Value: !GetAtt StreamsSampleDDBTable.StreamArn
```

Setelah Anda menerapkan templat pembentukan cloud ini, Anda dapat memasukkan Item Amazon DynamoDB berikut:

```
{
 "PK": "COMPANY#1000",
 "SK": "PRODUCT#CHOCOLATE#DARK",
 "company_id": "1000",
 "type": "",
 "state": "FL",
 "stores": 5,
 "price": 15,
 "quantity": 50,
 "fabric": "Florida Chocolates"
}
```

Berkat fungsi lambda sederhana yang disertakan sebaris dalam template pembentukan cloud ini, Anda akan melihat peristiwa di grup CloudWatch log Amazon untuk fungsi lambda sebagai berikut:

```
{
  "eventID": "c9fbe7d0261a5163fcb6940593e41797",
  "eventName": "INSERT",
  "eventVersion": "1.1",
  "eventSource": "aws:dynamodb",
  "awsRegion": "us-east-2",
  "dynamodb": {
    "ApproximateCreationDateTime": 1664559083.0,
    "Keys": {
      "SK": { "S": "PRODUCT#CHOCOLATE#DARK#1000" },
      "PK": { "S": "COMPANY#1000" }
    },
    "NewImage": {
      "quantity": { "N": "50" },
      "company_id": { "S": "1000" },
      "fabric": { "S": "Florida Chocolates" },
      "price": { "N": "15" },
      "stores": { "N": "5" },
      "product_id": { "S": "1000" },
      "SK": { "S": "PRODUCT#CHOCOLATE#DARK#1000" },
      "PK": { "S": "COMPANY#1000" },
      "state": { "S": "FL" },
      "type": { "S": "" }
    },
    "SequenceNumber": "700000000000888747038",
    "SizeBytes": 174,
    "StreamViewType": "NEW_AND_OLD_IMAGES"
  },
  "eventSourceARN": "arn:aws:dynamodb:us-east-2:111122223333:table/chocolate-table-StreamsSampleDDBTable-LUOI6UXQY7J1/stream/2022-09-30T17:05:53.209"
}
```

**Contoh Filter**
+ **Hanya produk yang cocok dengan status tertentu**

Contoh ini memodifikasi CloudFormation template untuk menyertakan filter untuk mencocokkan semua produk yang berasal dari Florida, dengan singkatan “FL”.

```
EventSourceDDBTableStream:
    Type: AWS::Lambda::EventSourceMapping
    Properties:
      BatchSize: 1
      Enabled: True
      FilterCriteria:
        Filters:
          - Pattern: '{ "dynamodb": { "NewImage": { "state": { "S": ["FL"] } } } }'
      EventSourceArn: !GetAtt StreamsSampleDDBTable.StreamArn
      FunctionName: !GetAtt ProcessEventLambda.Arn
      StartingPosition: LATEST
```

Setelah Anda menerapkan kembali tumpukan, Anda dapat menambahkan item DynamoDB berikut ke tabel. Perhatikan bahwa itu tidak akan muncul di log fungsi Lambda, karena produk dalam contoh ini berasal dari California.

```
{
 "PK": "COMPANY#1000",
 "SK": "PRODUCT#CHOCOLATE#DARK#1000",
 "company_id": "1000",
 "fabric": "Florida Chocolates",
 "price": 15,
 "product_id": "1000",
 "quantity": 50,
 "state": "CA",
 "stores": 5,
 "type": ""
}
```
+ **Hanya item yang dimulai dengan beberapa nilai di PK dan SK**

Contoh ini memodifikasi CloudFormation template untuk menyertakan kondisi berikut:

```
EventSourceDDBTableStream:
    Type: AWS::Lambda::EventSourceMapping
    Properties:
      BatchSize: 1
      Enabled: True
      FilterCriteria:
        Filters:
          - Pattern: '{"dynamodb": {"Keys": {"PK": { "S": [{ "prefix": "COMPANY" }] },"SK": { "S": [{ "prefix": "PRODUCT" }] }}}}'
      EventSourceArn: !GetAtt StreamsSampleDDBTable.StreamArn
      FunctionName: !GetAtt ProcessEventLambda.Arn
      StartingPosition: LATEST
```

Perhatikan kondisi AND mengharuskan kondisi berada di dalam pola, di mana PK dan SK Kunci berada dalam ekspresi yang sama dipisahkan oleh koma.

Baik mulai dengan beberapa nilai pada PK dan SK atau dari keadaan tertentu.

Contoh ini memodifikasi CloudFormation template untuk menyertakan kondisi berikut:

```
  EventSourceDDBTableStream:
    Type: AWS::Lambda::EventSourceMapping
    Properties:
      BatchSize: 1
      Enabled: True
      FilterCriteria:
        Filters:
          - Pattern: '{"dynamodb": {"Keys": {"PK": { "S": [{ "prefix": "COMPANY" }] },"SK": { "S": [{ "prefix": "PRODUCT" }] }}}}'
          - Pattern: '{ "dynamodb": { "NewImage": { "state": { "S": ["FL"] } } } }'
      EventSourceArn: !GetAtt StreamsSampleDDBTable.StreamArn
      FunctionName: !GetAtt ProcessEventLambda.Arn
      StartingPosition: LATEST
```

Perhatikan kondisi OR ditambahkan dengan memperkenalkan pola baru di bagian filter.

## Menyatukan semuanya - CDK
<a name="Streams.Lambda.Tutorial2.CDK"></a>

Contoh templat pembentukan proyek CDK berikut berjalan melalui fungsionalitas penyaringan acara. Sebelum bekerja dengan proyek CDK ini, Anda perlu [menginstal prasyarat](https://docs.aws.amazon.com/cdk/v2/guide/work-with.html) termasuk [ menjalankan skrip persiapan](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-python.html).

**Buat proyek CDK**

Pertama buat AWS CDK proyek baru, dengan memanggil `cdk init` dalam direktori kosong.

```
mkdir ddb_filters
cd ddb_filters
cdk init app --language python
```

Perintah `cdk init` menggunakan nama folder proyek untuk memberi nama berbagai elemen proyek, termasuk kelas, subfolder, dan file. Tanda hubung apa pun dalam nama folder diubah menjadi garis bawah. Nama tersebut harus mengikuti bentuk pengenal Python. Misalnya, seharusnya tidak dimulai dengan angka atau berisi spasi.

Untuk bekerja dengan proyek baru, aktifkan lingkungan virtualnya. Ini memungkinkan dependensi proyek diinstal secara lokal di folder proyek, bukan secara global.

```
source .venv/bin/activate
python -m pip install -r requirements.txt
```

**catatan**  
Anda mungkin mengenali ini sebagai Mac/Linux perintah untuk mengaktifkan lingkungan virtual. Templat Python menyertakan file batch, `source.bat`, yang memungkinkan perintah yang sama untuk digunakan pada Windows. Perintah Windows tradisional `.venv\Scripts\activate.bat` juga berfungsi. Jika Anda menginisialisasi AWS CDK proyek Anda menggunakan AWS CDK Toolkit v1.70.0 atau yang lebih lama, lingkungan virtual Anda ada di direktori, bukan. `.env` `.venv` 

**Infrastruktur Dasar**

Buka file `./ddb_filters/ddb_filters_stack.py` dengan editor teks pilihan Anda. File ini dibuat secara otomatis saat Anda membuat AWS CDK proyek. 

Selanjutnya, tambahkan fungsi `_create_ddb_table` dan `_set_ddb_trigger_function`. Fungsi-fungsi ini akan membuat tabel DynamoDB dengan kunci partisi PK dan mengurutkan kunci SK dalam mode penyediaan mode sesuai permintaan, dengan Amazon DynamoDB Streams diaktifkan secara default untuk menampilkan gambar Baru dan Lama.

Fungsi Lambda akan disimpan di folder `lambda` di bagian file `app.py`. File ini akan dibuat nanti. Ini akan mencakup variabel lingkungan `APP_TABLE_NAME`, yang akan menjadi nama Tabel Amazon DynamoDB yang dibuat oleh tumpukan ini. Dalam fungsi yang sama kami akan memberikan izin baca aliran ke fungsi Lambda. Akhirnya, hal tersebut akan berlangganan DynamoDB Streams sebagai sumber acara untuk fungsi lambda. 

Di akhir file dalam metode `__init__`, Anda akan memanggil konstruksi masing-masing untuk menginisialisasi mereka dalam tumpukan. Untuk proyek yang lebih besar yang memerlukan komponen dan layanan tambahan, mungkin yang terbaik adalah mendefinisikan konstruksi ini di luar tumpukan dasar. 

```
import os
import json

import aws_cdk as cdk
from aws_cdk import (
    Stack,
    aws_lambda as _lambda,
    aws_dynamodb as dynamodb,
)
from constructs import Construct


class DdbFiltersStack(Stack):

    def _create_ddb_table(self):
        dynamodb_table = dynamodb.Table(
            self,
            "AppTable",
            partition_key=dynamodb.Attribute(
                name="PK", type=dynamodb.AttributeType.STRING
            ),
            sort_key=dynamodb.Attribute(
                name="SK", type=dynamodb.AttributeType.STRING),
            billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST,
            stream=dynamodb.StreamViewType.NEW_AND_OLD_IMAGES,
            removal_policy=cdk.RemovalPolicy.DESTROY,
        )

        cdk.CfnOutput(self, "AppTableName", value=dynamodb_table.table_name)
        return dynamodb_table

    def _set_ddb_trigger_function(self, ddb_table):
        events_lambda = _lambda.Function(
            self,
            "LambdaHandler",
            runtime=_lambda.Runtime.PYTHON_3_9,
            code=_lambda.Code.from_asset("lambda"),
            handler="app.handler",
            environment={
                "APP_TABLE_NAME": ddb_table.table_name,
            },
        )

        ddb_table.grant_stream_read(events_lambda)

        event_subscription = _lambda.CfnEventSourceMapping(
            scope=self,
            id="companyInsertsOnlyEventSourceMapping",
            function_name=events_lambda.function_name,
            event_source_arn=ddb_table.table_stream_arn,
            maximum_batching_window_in_seconds=1,
            starting_position="LATEST",
            batch_size=1,
        )

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        ddb_table = self._create_ddb_table()
        self._set_ddb_trigger_function(ddb_table)
```

Sekarang kita akan membuat fungsi lambda yang sangat sederhana yang akan mencetak log ke Amazon CloudWatch. Untuk melakukannya, buat folder baru bernama `lambda`.

```
mkdir lambda
touch app.py
```

Menggunakan editor teks favorit Anda, tambahkan konten berikut ke file `app.py`:

```
import logging

LOGGER = logging.getLogger()
LOGGER.setLevel(logging.INFO)


def handler(event, context):
    LOGGER.info('Received Event: %s', event)
    for rec in event['Records']:
        LOGGER.info('Record: %s', rec)
```

Memastikan Anda berada di folder `/ddb_filters/`, ketikkan perintah berikut untuk membuat aplikasi sampel:

```
cdk deploy
```

Pada titik tertentu Anda akan diminta untuk mengonfirmasi apakah Anda ingin menerapkan solusi tersebut. Terima perubahan dengan mengetik `Y`.

```
├───┼──────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${LambdaHandler/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴──────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘

Do you wish to deploy these changes (y/n)? y

...

✨  Deployment time: 67.73s

Outputs:
DdbFiltersStack.AppTableName = DdbFiltersStack-AppTable815C50BC-1M1W7209V5YPP
Stack ARN:
arn:aws:cloudformation:us-east-2:111122223333:stack/DdbFiltersStack/66873140-40f3-11ed-8e93-0a74f296a8f6
```

Setelah perubahan diterapkan, buka AWS konsol Anda dan tambahkan satu item ke tabel Anda. 

```
{
 "PK": "COMPANY#1000",
 "SK": "PRODUCT#CHOCOLATE#DARK",
 "company_id": "1000",
 "type": "",
 "state": "FL",
 "stores": 5,
 "price": 15,
 "quantity": 50,
 "fabric": "Florida Chocolates"
}
```

 CloudWatch Log sekarang harus berisi semua informasi dari entri ini. 

**Contoh Filter**
+ **Hanya produk yang cocok dengan status tertentu**

Buka file `ddb_filters/ddb_filters/ddb_filters_stack.py`, dan modifikasi untuk menyertakan filter yang cocok dengan semua produk yang setara dengan “FL”. Ini dapat direvisi tepat di bawah `event_subscription` di baris 45.

```
event_subscription.add_property_override(
    property_path="FilterCriteria",
    value={
        "Filters": [
            {
                "Pattern": json.dumps(
                    {"dynamodb": {"NewImage": {"state": {"S": ["FL"]}}}}
                )
            },
        ]
    },
)
```
+ **Hanya item yang dimulai dengan beberapa nilai di PK dan SK**

Ubah skrip python untuk menyertakan kondisi berikut:

```
event_subscription.add_property_override(
    property_path="FilterCriteria",
    value={
        "Filters": [
            {
                "Pattern": json.dumps(
                    {
                        {
                            "dynamodb": {
                                "Keys": {
                                    "PK": {"S": [{"prefix": "COMPANY"}]},
                                    "SK": {"S": [{"prefix": "PRODUCT"}]},
                                }
                            }
                        }
                    }
                )
            },
        ]
    },
```
+ **Baik mulai dengan beberapa nilai pada PK dan SK atau dari keadaan tertentu.**

Ubah skrip python untuk menyertakan kondisi berikut:

```
event_subscription.add_property_override(
    property_path="FilterCriteria",
    value={
        "Filters": [
            {
                "Pattern": json.dumps(
                    {
                        {
                            "dynamodb": {
                                "Keys": {
                                    "PK": {"S": [{"prefix": "COMPANY"}]},
                                    "SK": {"S": [{"prefix": "PRODUCT"}]},
                                }
                            }
                        }
                    }
                )
            },
            {
                "Pattern": json.dumps(
                    {"dynamodb": {"NewImage": {"state": {"S": ["FL"]}}}}
                )
            },
        ]
    },
)
```

Perhatikan bahwa kondisi OR ditambahkan dengan menambahkan lebih banyak elemen ke array Filter.

**Pembersihan**

Temukan tumpukan filter di dasar direktori kerja Anda, dan jalankan`cdk destroy`. Anda akan diminta untuk mengonfirmasi penghapusan sumber daya:

```
cdk destroy
Are you sure you want to delete: DdbFiltersStack (y/n)? y
```

# Praktik terbaik menggunakan DynamoDB Streams dengan Lambda
<a name="Streams.Lambda.BestPracticesWithDynamoDB"></a>

 AWS Lambda Fungsi berjalan di dalam *wadah* —lingkungan eksekusi yang diisolasi dari fungsi lain. Ketika Anda menjalankan fungsi untuk pertama kalinya, AWS Lambda membuat wadah baru dan mulai mengeksekusi kode fungsi.

Fungsi Lambda memiliki *handler* yang dijalankan sekali per permohonan. Handler berisi logika bisnis utama untuk fungsi. Misalnya, fungsi Lambda yang ditampilkan dalam [Langkah 4: Buat dan uji fungsi Lambda](Streams.Lambda.Tutorial.md#Streams.Lambda.Tutorial.LambdaFunction) memiliki handler yang dapat memproses catatan dalam DynamoDB stream. 

Anda juga dapat memberikan kode inisialisasi yang hanya berjalan satu kali—setelah penampung dibuat, tetapi sebelumnya AWS Lambda menjalankan handler untuk pertama kalinya. Fungsi Lambda yang ditampilkan di [Langkah 4: Buat dan uji fungsi Lambda](Streams.Lambda.Tutorial.md#Streams.Lambda.Tutorial.LambdaFunction) memiliki kode inisialisasi yang mengimpor SDK untuk JavaScript di Node.js, dan membuat klien untuk Amazon SNS. Objek-objek ini hanya boleh didefinisikan sekali, di luar handler.

Setelah fungsi berjalan, AWS Lambda mungkin memilih untuk menggunakan kembali wadah untuk pemanggilan fungsi berikutnya. Dalam kasus ini, handler fungsi Anda mungkin dapat menggunakan kembali sumber daya yang Anda tetapkan dalam kode inisialisasi Anda. (Anda tidak dapat mengontrol berapa lama AWS Lambda akan mempertahankan kontainer, atau apakah kontainer akan digunakan kembali.)

Untuk pemicu DynamoDB AWS Lambda menggunakan, kami merekomendasikan hal berikut:
+ AWS klien layanan harus dipakai dalam kode inisialisasi, bukan di handler. Ini memungkinkan AWS Lambda untuk menggunakan kembali koneksi yang ada, selama masa pakai kontainer.
+ Secara umum, Anda tidak perlu secara eksplisit mengelola koneksi atau menerapkan penyatuan koneksi karena AWS Lambda mengelola ini untuk Anda.

Konsumen Lambda untuk aliran DynamoDB tidak menjamin persis sekali pengiriman dan dapat menyebabkan duplikat sesekali. Pastikan kode fungsi Lambda Anda idempoten untuk mencegah timbulnya masalah tak terduga karena pemrosesan duplikat.

Untuk informasi selengkapnya, lihat [Praktik terbaik untuk bekerja dengan AWS Lambda fungsi](https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html) di *Panduan AWS Lambda Pengembang*.

# DynamoDB Streams dan Apache Flink
<a name="StreamsApacheFlink.xml"></a>

Anda dapat menggunakan catatan Amazon DynamoDB Streams dengan Apache Flink. Dengan [Amazon Managed Service untuk Apache Flink](https://aws.amazon.com/managed-service-apache-flink/), Anda dapat mengubah dan menganalisis data streaming secara real time menggunakan Apache Flink. Apache Flink adalah kerangka pemrosesan aliran sumber terbuka untuk memproses data real-time. Konektor Amazon DynamoDB Streams untuk Apache Flink menyederhanakan pembuatan dan pengelolaan beban kerja Apache Flink dan memungkinkan Anda mengintegrasikan aplikasi dengan aplikasi lain. Layanan AWS

Amazon Managed Service untuk Apache Flink membantu Anda membangun aplikasi pemrosesan end-to-end streaming dengan cepat untuk analitik log, analitik clickstream, Internet of Things (IoT), teknologi iklan, game, dan banyak lagi. Empat kasus penggunaan yang paling umum adalah streaming extract-transform-load (ETL), aplikasi berbasis peristiwa, analitik real-time responsif, dan kueri interaktif aliran data. [Untuk informasi selengkapnya tentang menulis ke Apache Flink dari Amazon DynamoDB Streams, lihat Amazon DynamoDB Streams Connector.](https://nightlies.apache.org/flink/flink-docs-master/docs/connectors/datastream/dynamodb/)