

# Trabalhar com tabelas, itens, consultas, verificações e índices
<a name="WorkingWithDynamo"></a>

Esta seção fornece detalhes sobre como trabalhar com tabelas, itens, consultas e muito mais no Amazon DynamoDB.

**Topics**
+ [Trabalhar com tabelas e dados no DynamoDB](WorkingWithTables.md)
+ [Tabelas globais: replicação multiativa e multirregional](GlobalTables.md)
+ [Trabalhar com itens e atributos no DynamoDB](WorkingWithItems.md)
+ [Melhorar o acesso aos dados com índices secundários no DynamoDB](SecondaryIndexes.md)
+ [Gerenciar fluxos de trabalho complexos com transações do DynamoDB](transactions.md)
+ [Captura de dados de alterações com o Amazon DynamoDB](streamsmain.md)

# Trabalhar com tabelas e dados no DynamoDB
<a name="WorkingWithTables"></a>

Esta seção descreve como usar a AWS Command Line Interface (AWS CLI) e os AWS SDKs para criar, atualizar e excluir tabelas no Amazon DynamoDB.

**nota**  
Você também pode executar essas mesmas tarefas usando o Console de gerenciamento da AWS. Para obter mais informações, consulte [Utilizar o console](AccessingDynamoDB.md#ConsoleDynamoDB).

Esta seção também fornece mais informações sobre a capacidade de throughput usando o Auto Scaling do DynamoDB ou configurando manualmente o throughput provisionado.

**Topics**
+ [Operações básicas em tabelas do DynamoDB](WorkingWithTables.Basics.md)
+ [Considerações ao escolher uma classe de tabela no DynamoDB](WorkingWithTables.tableclasses.md)
+ [Adicionar etiquetas e rótulos a recursos no DynamoDB](Tagging.md)

# Operações básicas em tabelas do DynamoDB
<a name="WorkingWithTables.Basics"></a>

De forma semelhante a outros sistemas de banco de dados, o Amazon DynamoDB armazena dados em tabelas. É possível gerenciar suas tabelas usando algumas operações básicas.

**Topics**
+ [Criar uma tabela](#WorkingWithTables.Basics.CreateTable)
+ [Descrever uma tabela](#WorkingWithTables.Basics.DescribeTable)
+ [Atualizar uma tabela](#WorkingWithTables.Basics.UpdateTable)
+ [Excluir uma tabela](#WorkingWithTables.Basics.DeleteTable)
+ [Usar a proteção contra exclusão](#WorkingWithTables.Basics.DeletionProtection)
+ [Nomes de tabela de listagem](#WorkingWithTables.Basics.ListTables)
+ [Descrever cotas de throughput provisionado](#WorkingWithTables.Basics.DescribeLimits)

## Criar uma tabela
<a name="WorkingWithTables.Basics.CreateTable"></a>

Use a operação `CreateTable` para criar uma tabela no Amazon DynamoDB. Para criar a tabela, você deve fornecer as seguintes informações:
+ **O nome da tabela.** O nome deve estar de acordo com as regras de nomenclatura do DynamoDB e deve ser exclusivo na conta e na região atuais da AWS. Por exemplo, você poderia criar uma tabela `People` no Leste dos EUA (Norte da Virgínia) e outra tabela `People` na Europa (Irlanda). No entanto, essas duas tabelas devem ser inteiramente diferente uma da outra. Para obter mais informações, consulte [Tipos de dados compatíveis e regras de nomenclatura no Amazon DynamoDB](HowItWorks.NamingRulesDataTypes.md).
+ **chave primária.** A chave primária pode consistir em um atributo (chave de partição) ou de dois atributos (chave de partição e chave de classificação). Você precisa fornecer os nomes de atributos, os tipos de dados e a função de cada um: `HASH` (para uma chave de partição) e `RANGE` (para uma chave de classificação). Para obter mais informações, consulte [Chave primária](HowItWorks.CoreComponents.md#HowItWorks.CoreComponents.PrimaryKey).
+ **Configurações de throughput (para tabelas provisionadas).** Se estiver usando o modo provisionado, você deve especificar as configurações de throughput de leitura e gravação inicial da tabela. Você pode modificar essas configurações mais tarde ou habilitar o Auto Scaling do DynamoDB para gerenciar as configurações para você. Para obter mais informações, consulte [Modo de capacidade provisionada do DynamoDB](provisioned-capacity-mode.md) e [Gerenciar a capacidade de throughput automaticamente com o ajuste de escala automático do DynamoDB](AutoScaling.md).

### Exemplo 1: criar uma tabela sob demanda
<a name="create-payperrequest-example"></a>

Para criar a mesma tabela `Music` usando modo sob demanda.

```
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
```

A operação `CreateTable` retorna metadados para a tabela, conforme mostrado a seguir.

```
{
    "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
    }
}
```

**Importante**  
 Ao chamar `DescribeTable` em uma tabela sob demanda, as unidades de capacidade de leitura e unidades de capacidade de gravação são definidas como 0. 

### Exemplo 2: criar uma tabela provisionada
<a name="create-provisioned-example"></a>

O exemplo da AWS CLI a seguir mostra como criar uma tabela (`Music`). A chave primária consiste em `Artist` (chave de partição) e `SongTitle` (chave de classificação), cada uma delas tem um tipo de dados de `String`. O throughput máximo da tabela é 10 unidades de capacidade de leitura e 5 unidades de capacidade de gravação.

```
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
```

A operação `CreateTable` retorna metadados para a tabela, conforme mostrado a seguir.

```
{
    "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
    }
}
```

O elemento `TableStatus` indica o estado atual da tabela (`CREATING`). Pode demorar um pouco para criar a tabela, dependendo dos valores que você especificar para `ReadCapacityUnits` e `WriteCapacityUnits`. Valores maiores exigem que o DynamoDB aloque mais recursos para a tabela.

### Exemplo 3: criar uma tabela usando a classe de tabela Standard-Infrequent Access do DynamoDB
<a name="create-infrequent-access-example"></a>

Para criar a mesma tabela de `Music` usando a classe de tabela Standard-Infrequent Access (Padrão – Acesso Infrequente) do 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
```

A operação `CreateTable` retorna metadados para a tabela, conforme mostrado a seguir.

```
{
    "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
    }
}
```

## Descrever uma tabela
<a name="WorkingWithTables.Basics.DescribeTable"></a>

Para visualizar detalhes sobre uma tabela, use a operação `DescribeTable`. Você deve fornecer o nome da tabela. A saída de `DescribeTable` está no mesmo formato de `CreateTable`. Ela inclui o a marca de data e hora em que a tabela foi criada, o esquema de chaves, as configurações de throughput provisionado, o tamanho estimado e os índices secundários que estão presentes.

**Importante**  
 Ao chamar `DescribeTable` em uma tabela sob demanda, as unidades de capacidade de leitura e unidades de capacidade de gravação são definidas como 0. 

**Example**  

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

A tabela estará pronta para uso quando `TableStatus` tiver sido alterado de `CREATING` para `ACTIVE`.

**nota**  
Se você emitir uma solicitação `DescribeTable` imediatamente após uma solicitação `CreateTable`, o DynamoDB poderá retornar um erro (`ResourceNotFoundException`). Isso ocorre porque `DescribeTable` usa uma consulta eventualmente consistente e os metadados da sua tabela podem não estar disponíveis nesse momento. Aguarde alguns segundos e, em seguida, tente a solicitação `DescribeTable` novamente.  
Para fins de faturamento, os custos de armazenamento do DynamoDB incluem uma sobrecarga de 100 bytes por item. (Para obter mais informações, acesse a [Preços do DynamoDB](https://aws.amazon.com/dynamodb/pricing/).) Esses 100 bytes extras por item são usados em cálculos da unidade de capacidade ou pela operação `DescribeTable`. 

## Atualizar uma tabela
<a name="WorkingWithTables.Basics.UpdateTable"></a>

A operação `UpdateTable` permite que você execute uma das seguintes ações:
+ Modificar as configurações de throughput provisionad de uma tabela (para tabelas de modo provisionadas).
+ Alterar o modo de capacidade de leitura/gravação de tabela.
+ Manipular índices secundários globais na tabela (consulte [Como usar índices secundários globais no DynamoDB](GSI.md)).
+ Habilite ou desabilite o DynamoDB Streams na tabela (consulte [Capturar dados de alterações para o DynamoDB Streams](Streams.md)).

**Example**  
O exemplo de AWS CLI a seguir mostra como modificar as configurações de throughput provisionado de uma tabela.  

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

**nota**  
Quando você emite uma solicitação `UpdateTable`, o status da tabela muda de `AVAILABLE` para `UPDATING`. A tabela permanecerá totalmente disponível para uso enquanto estiver `UPDATING`. Quando esse processo for concluído, o status da tabela mudará de `UPDATING` para `AVAILABLE`.

**Example**  
O exemplo de AWS CLI a seguir mostra como modificar o modo de capacidade de leitura/gravação de uma tabela para o modo sob demanda.  

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

## Excluir uma tabela
<a name="WorkingWithTables.Basics.DeleteTable"></a>

Você pode remover uma tabela não utilizada com a operação `DeleteTable`. Excluir uma tabela é uma operação irrecuperável. Para excluir uma tabela usando o Console de gerenciamento da AWS, consulte [Etapa 6: (Opcional) exclua uma tabela do DynamoDB para limpar os recursos](getting-started-step-6.md).

**Example**  
O exemplo de AWS CLI a seguir mostra como excluir uma tabela.  

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

Quando você emite uma solicitação `DeleteTable`, o status da tabela muda de `ACTIVE` para `DELETING`. A exclusão da tabela pode demorar um pouco, dependendo dos recursos que ela usa (como os dados armazenados e os streams ou índices da tabela).

Quando a operação `DeleteTable` é concluída, a tabela deixa de existir no DynamoDB.

## Usar a proteção contra exclusão
<a name="WorkingWithTables.Basics.DeletionProtection"></a>

É possível proteger uma tabela contra exclusão acidental com a propriedade de proteção contra exclusão. Habilitar essa propriedade para tabelas ajuda a garantir que elas não sejam excluídas acidentalmente durante as operações regulares de gerenciamento de tabelas pelos administradores. Isso ajudará a evitar interrupções nas operações empresariais normais.

 O proprietário da tabela ou um administrador autorizado controla a propriedade de proteção contra exclusão de cada tabela. A propriedade de proteção contra exclusão de cada tabela está desativada por padrão. Isso inclui réplicas globais e tabelas restauradas com base em backups. Quando a proteção contra exclusão está desabilitada para uma tabela, ela pode ser excluída por qualquer usuário autorizado por uma política do Identity and Access Management (IAM). Quando a proteção contra exclusão está habilitada para uma tabela, ninguém pode excluí-la. 

Para alterar essa configuração, acesse **Configurações adicionais** da tabela, navegue até o painel **Proteção contra exclusão** e selecione **Ativar Proteção contra exclusão**. 

A propriedade de proteção contra exclusão é compatível com o console do DynamoDB, API, CLI/SDK e CloudFormation. A API `CreateTable` é compatível com a propriedade de proteção contra exclusão no momento da criação da tabela, e a API `UpdateTable` é compatível com a alteração da propriedade de proteção contra exclusão para tabelas existentes.

**nota**  
Se uma conta da AWS for excluída, todos os dados dessa conta, incluindo as tabelas, também serão excluídos em 90 dias.
Se o DynamoDB perder o acesso a uma chave gerenciada pelo cliente que foi usada para criptografar uma tabela, ela ainda será arquivada. O arquivamento requer um backup da tabela e a exclusão da original.

## Nomes de tabela de listagem
<a name="WorkingWithTables.Basics.ListTables"></a>

A operação `ListTables` retorna os nomes das tabelas do DynamoDB da conta e da região atuais da AWS.

**Example**  
O exemplo da AWS CLI a seguir mostra como listar os nomes de tabelas do DynamoDB.  

```
aws dynamodb list-tables
```

## Descrever cotas de throughput provisionado
<a name="WorkingWithTables.Basics.DescribeLimits"></a>

A operação `DescribeLimits` retorna as cotas de capacidade de leitura e gravação atuais da conta e da região atuais da AWS.

**Example**  
O exemplo de AWS CLI a seguir mostra como descrever as cotas atuais de throughput provisionado.  

```
aws dynamodb describe-limits
```
A saída mostra as cotas superiores das unidades de capacidade de leitura e gravação da conta e da região atuais da AWS.

Para obter mais informações sobre essas cotas e como solicitar aumentos de cota, consulte [Cotas padrão de throughput](ServiceQuotas.md#default-limits-throughput).

# Considerações ao escolher uma classe de tabela no DynamoDB
<a name="WorkingWithTables.tableclasses"></a>

O DynamoDB apresenta duas classes de tabela projetadas para ajudar você a otimizar o custo. A classe de tabela Standard do DynamoDB é a padrão e é recomendada para a grande maioria das workloads. A classe de tabela do DynamoDB Standard-Infrequent Access (DynamoDB Standard-IA) é otimizada para tabelas em que o armazenamento é o custo dominante. Por exemplo, tabelas que armazenam dados acessados com pouca frequência, como logs da aplicação, postagens antigas de mídia social, histórico de pedidos de comércio eletrônico e antigas conquistas de jogos, são bons candidatos para a classe de tabela Standard-IA.

Cada tabela do DynamoDB está associada a uma classe de tabela. Todos os índices secundários associados à tabela usam a mesma classe de tabela. Você pode definir sua classe de tabela ao criar sua tabela (DynamoDB Standard por padrão) e atualizar a classe de tabela de uma tabela existente usando o Console de gerenciamento da AWS, a CLI da AWS ou o AWS SDK. O DynamoDB também permite o gerenciamento de sua classe de tabela usando o AWS CloudFormation para tabelas de região única (tabelas que não são tabelas globais). Cada classe de tabela oferece preços diferentes para armazenamento de dados, bem como para solicitações de leitura e gravação. Ao escolher uma classe de tabela para sua tabela, lembre-se do seguinte:
+ A classe de tabela Standard do DynamoDB oferece custos de throughput mais baixos do que o DynamoDB Standard-IA e é a opção mais econômica para tabelas em que o throughput é o custo dominante. 
+ A classe de tabela DynamoDB Standard-IA oferece custos de armazenamento mais baixos do que o DynamoDB Standard e é a opção mais econômica para tabelas em que o armazenamento é o custo dominante. Quando o armazenamento excede 50% do custo de throughput (leituras e gravações) de uma tabela usando a classe de tabela Standard do DynamoDB, a classe de tabela DynamoDB Standard-IA pode ajudá-lo a reduzir o custo total da tabela. 
+ As tabelas DynamoDB Standard – IA oferecem a mesma performance, durabilidade e disponibilidade que as tabelas padrão do DynamoDB. 
+ A alternância entre as classes de tabela DynamoDB Standard e DynamoDB Standard – IA não requer a alteração do código da aplicação. Você usa as mesmas APIs do DynamoDB e endpoints de serviço, independentemente da classe de tabela que suas tabelas utilizem. 
+ As tabelas do DynamoDB Standard – IA são compatíveis com todos os recursos existentes do DynamoDB, como autoescalabilidade, modo sob demanda, vida útil (TTL), backups sob demanda, recuperação em um ponto anterior no tempo (PITR) e índices secundários globais.

A classe de tabela mais econômica para sua tabela depende dos padrões de uso de armazenamento e throughput esperados da tabela. Você pode ver o histórico de armazenamento e o custo de throughput da sua tabela com o AWS Cost and Usage Reports e o AWS Cost Explorer. Use esses dados de histórico para determinar a classe de tabela mais econômica para sua tabela. Para saber mais sobre o uso do AWS Cost and Usage Reports e o AWS Cost Explorer, veja a [Documentação de Billing and Cost Management do AWS](https://docs.aws.amazon.com/account-billing/index.html). Para mais informações sobre a precificação das classes de tabela, acesse [Preço do Amazon DynamoDB](https://aws.amazon.com/dynamodb/pricing/on-demand/).

**nota**  
Uma atualização de classe de tabela é um processo em segundo plano. Você ainda pode acessar sua tabela normalmente durante uma atualização de classe de tabela. O tempo para atualizar sua classe de tabela depende do tráfego da tabela, do tamanho do armazenamento e de outras variáveis relacionadas. Não são permitidas mais do que duas atualizações de classe de tabela em sua tabela em um período de trilha de 30 dias.

# Adicionar etiquetas e rótulos a recursos no DynamoDB
<a name="Tagging"></a>

Você pode rotular os recursos do Amazon DynamoDB com *tags*. As tags permitem categorizar recursos de diferentes maneiras, por exemplo, por finalidade, proprietário, ambiente ou outros critérios. As tags podem ajudar a fazer o seguinte:
+ Identificar rapidamente um recurso com base nas tags que você atribuiu a ele.
+ Veja as faturas da AWS discriminadas por tags.
**nota**  
Todos os índices secundários locais (LSI) e índices secundários globais (GSI) relacionados a tabelas marcadas são rotulados com as mesmas tags automaticamente. Atualmente, o uso de Streams pelo DynamoDB não pode ser marcado.

A marcação é suportada por serviços da AWS como Amazon EC2, Amazon S3, DynamoDB e outros. Uma marcação eficiente é capaz de fornecer insights de custos, permitindo criar relatórios entre serviços que possuem uma tag específica.

Para começar a usar tags, faça o seguinte:

1. Compreender [Restrições de marcação no DynamoDB](#TaggingRestrictions).

1. Criar tags usando [Marcar recursos no DynamoDB](Tagging.Operations.md).

1. Use [Usar etiquetas do DynamoDB para criar relatórios de alocação de custos](#CostAllocationReports) para controlar seus custos da AWS por tag ativa.

Por fim, é recomendável seguir estratégias de marcação ideais. Para obter informações, consulte [Estratégias de marcação da AWS](https://d0.awsstatic.com/aws-answers/AWS_Tagging_Strategies.pdf).

## Restrições de marcação no DynamoDB
<a name="TaggingRestrictions"></a>

 Cada tag consiste em uma chave e um valor, ambos definidos por você. As seguintes restrições são aplicáveis: 
+  Cada tabela do DynamoDB pode ter apenas uma tag com a mesma chave. Se você tentar adicionar uma tag existente (mesma chave), o valor da tag existente será atualizado para o novo valor. 
+  As chaves e valores das tags diferenciam maiúsculas de minúsculas. 
+  O comprimento máximo da chave é 128 caracteres Unicode. 
+ O número máximo de tags que você pode atribuir a um recurso é 256. 
+  Os caracteres permitidos são letras, espaço em branco e números, além dos seguintes caracteres especiais: `+ - = . _ : /` 
+  O número máximo de tags por recurso é 50.
+ O tamanho máximo aceito para todas as tags em uma tabela é de 10 KB.
+ Nomes e valores de tags atribuídos pela AWS recebem automaticamente o prefixo `aws:`, o qual não pode ser atribuído por você. Nomes de tags atribuídos pela AWS não contam para o limite de tag de recurso definido pelo usuário de 50 ou o limite máximo de tamanho de 10 KB. Nomes de tags atribuídos pelo usuário têm o prefixo `user:` no relatório de alocação de custos. 
+  Não é possível colocar uma data retroativa na aplicação de uma tag. 

# Marcar recursos no DynamoDB
<a name="Tagging.Operations"></a>

Você pode usar o console do Amazon DynamoDB ou a AWS Command Line Interface (AWS CLI) para adicionar, listar, editar ou excluir tags. Em seguida, você pode ativar essas tags definidas pelo usuário para que elas apareçam no console do Gerenciamento de Faturamento e Custos da AWS para o controle da alocação de custos. Para obter mais informações, consulte [Usar etiquetas do DynamoDB para criar relatórios de alocação de custos](Tagging.md#CostAllocationReports). 

 Para edição em massa, também é possível usar o Tag Editor no Console de gerenciamento da AWS. Para obter mais informações, consulte [Trabalhar com o Tag Editor](https://docs.aws.amazon.com/awsconsolehelpdocs/latest/gsg/tag-editor.html).

 Para usar a API do DynamoDB, consulte as operações a seguir na [Referência da API do 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**
+ [Configuração de permissões para filtrar por tags](#Tagging.Operations.permissions)
+ [Adição de tags a tabelas novas ou existentes (Console de gerenciamento da AWS)](#Tagging.Operations.using-console)
+ [Adição de tags a tabelas novas ou existentes (AWS CLI)](#Tagging.Operations.using-cli)

## Configuração de permissões para filtrar por tags
<a name="Tagging.Operations.permissions"></a>

Para usar etiquetas a fim de filtrar sua lista de tabelas no console do DynamoDB, as políticas do seu usuário devem incluir acesso às seguintes operações:
+ `tag:GetTagKeys`
+ `tag:GetTagValues`

Para acessar essas operações, anexe uma nova política do IAM ao seu usuário seguindo as etapas abaixo.

1. Acesse o [console do IAM](https://console.aws.amazon.com/iam/) com um usuário administrativo.

1. No painel de navegação à esquerda, selecione "Policies" (Políticas).

1. Selecione "Create Policy" (Criar política).

1. No editor, a política a seguir no editor de JSON.

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

****  

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

------

1. Conclua o assistente e atribua um nome à política (por exemplo, `TagKeysAndValuesReadAccess`).

1. No menu de navegação à esquerda, selecione "Users" (Usuários).

1. Na lista, selecione o usuário que você normalmente usa para acessar o console do DynamoDB.

1. Selecione "Add permissions" (Adicionar permissões).

1. Selecione "Attach existing policies directly" (Anexar políticas existentes diretamente).

1. Na lista, selecione a política que você criou anteriormente.

1. Assista todo o assistente.

## Adição de tags a tabelas novas ou existentes (Console de gerenciamento da AWS)
<a name="Tagging.Operations.using-console"></a>

Você pode usar o console do DynamoDB para adicionar tags a novas tabelas ao criá-las, ou para adicionar, editar ou excluir tags de tabelas existentes.

**Para marcar recursos na criação (console)**

1. Faça login no Console de gerenciamento da AWS e abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/).

1. No painel de navegação, selecione **Tabelas** e **Criar tabela**.

1. Na página **Create DynamoDB table (Criar tabela DynamoDB)**, forneça um nome e uma chave primária. Na seção **Tags (Etiquetas)**, escolha **Add new tag (Adicionar nova etiqueta)** e insira as etiquetas que você deseja usar.

   Para obter informações sobre a estrutura da tag, consulte [Restrições de marcação no DynamoDB](Tagging.md#TaggingRestrictions). 

   Para obter mais informações sobre como criar tabelas, consulte [Operações básicas em tabelas do DynamoDB](WorkingWithTables.Basics.md).

**Para marcar recursos existentes (console)**

Abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/).

1. No painel de navegação, selecione **Tables** (Tabelas).

1. Escolha uma tabela na lista e escolha a guia **Additional settings (Configurações adicionais)**. Você pode adicionar, editar ou excluir seus marcadores na seção **Tags (Etiquetas)** na parte inferior da página.

## Adição de tags a tabelas novas ou existentes (AWS CLI)
<a name="Tagging.Operations.using-cli"></a>

Os exemplos a seguir mostram como usar a AWS CLI para especificar tags ao criar tabelas e índices e para marcar recursos existentes.

**Para marcar recursos na criação (AWS CLI)**
+ O exemplo a seguir cria uma nova tabela `Movies` e adiciona a tag `Owner` com um valor de `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
  ```

**Para marcar recursos existentes (AWS CLI)**
+ O exemplo a seguir adiciona a tag `Owner` com um valor de `blueTeam` à tabela `Movies`: 

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

**Para listar todas as tags de uma tabela (AWS CLI)**
+ O exemplo a seguir relaciona todas as tags associadas à tabela `Movies`.

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

## Usar etiquetas do DynamoDB para criar relatórios de alocação de custos
<a name="CostAllocationReports"></a>

A AWS usa tags para organizar os custos de recursos no seu relatório de alocação de custos. A AWS fornece dois tipos de tags alocação de custos:
+ Uma tag gerada pela AWS. A AWS define, cria e aplica essa tag para você.
+ Tags definidas pelo usuário. Você define, cria e aplica essas tags.

É necessário ativar os dois tipos de tags separadamente para que elas possam ser exibidas no Cost Explorer ou em um relatório de alocação de custos. 

 Para ativar tags geradas pela AWS: 

1.  Faça login no Console de gerenciamento da AWS e abra o console do Billing and Cost Management em [https://console.aws.amazon.com/billing/home\$1/](https://console.aws.amazon.com/billing/home#/.). 

1.  No painel de navegação, escolha **Cost Allocation Tags**. 

1.  Em **AWSGenerated Cost Allocation Tags (Etiquetas de alocação de custos geradas)**, escolha **Activate (Ativar)**. 

 Para ativar tags definidas pelo usuário: 

1.  Faça login no Console de gerenciamento da AWS e abra o console do Billing and Cost Management em [https://console.aws.amazon.com/billing/home\$1/](https://console.aws.amazon.com/billing/home#/.). 

1.  No painel de navegação, escolha **Cost Allocation Tags**. 

1.  Em **Tags de alocação de custos definidos pelo usuário**, escolha **Ativar**. 

 Após você criar e ativar tags, a AWS gera um relatório de alocação de custos com a utilização e os custos agrupados de acordo com as tags ativas. O relatório de alocação de custos inclui todos os seus custos da AWS para cada período de faturamento. O relatório inclui recursos com e sem tags, para que você possa organizar claramente as cobranças de cada um deles. 

**nota**  
 No momento, os dados transferidos do DynamoDB não são categorizados por tags em relatórios de alocação de custos. 

 Para obter mais informações, consulte [Usar tags de alocação de custos](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html). 

# Tabelas globais: replicação multiativa e multirregional
<a name="GlobalTables"></a>

As *tabelas globais do Amazon DynamoDB* são um atributo de banco de dados totalmente gerenciado, multiativo e multirregional que fornece replicação de dados fácil de usar e performance de leitura e gravação local rápida para aplicações globalmente escaladas.

As tabelas globais replicam automaticamente os dados de tabela do DynamoDB em várias Regiões da AWS e, opcionalmente, em várias contas da AWSsem exigir que você crie e mantenha sua própria solução de replicação. As tabelas globais são ideais para aplicativos que exigem continuidade de negócios e alta disponibilidade por meio da implantação em várias regiões. Qualquer réplica de tabela global pode servir para leituras e gravações. Os aplicativos podem alcançar alta resiliência com um objetivo de ponto de recuperação (RPO) baixo ou zero, transferindo o tráfego para uma região diferente se o processamento do aplicativo for interrompido em uma região. As tabelas globais estão disponíveis em todas as regiões onde o DynamoDB está disponível.

## Modos de consistência
<a name="GlobalTables.consistency-modes"></a>

Ao criar uma tabela global, você pode configurar o modo de consistência. As tabelas globais permitem dois modos de consistência: consistência final multirregional (MREC) e consistência forte multirregional (MRSC).

Se você não especificar um modo de consistência ao criar uma tabela global, ela usará como padrão a consistência final multirregional (MREC). Uma tabela global não pode conter réplicas configuradas com modos de consistência diferentes. Não é possível alterar o modo de consistência de uma tabela global depois da criação.

## Configurações da conta
<a name="GlobalTables.account-configurations"></a>

O DynamoDB agora permite dois modelos de tabelas globais, cada um criado para padrões de arquitetura diferentes:
+ **Tabelas globais da mesma conta**: todas as réplicas são criadas e gerenciadas em uma única conta da AWS.
+ **Tabelas globais de várias contas**: as réplicas são implantadas em várias contas da AWS enquanto fazem parte de um grupo de replicação compartilhado.

Os modelos da mesma conta e de várias contas permitem gravações em várias regiões, replicação assíncrona, resolução de conflitos com o método “último gravador prevalece” e o mesmo modelo de faturamento. No entanto, eles diferem com relação à forma como as contas, as permissões, a criptografia e a governança de tabelas são gerenciadas.

As tabelas globais configuradas para a MRSC permitem somente configurações da mesma conta.

Você pode configurar uma tabela global usando o AWS Management Console. As tabelas globais usam as APIs existentes do DynamoDB para ler e gravar dados em suas tabelas, portanto, nenhuma alteração no aplicativo é necessária. Você paga apenas pelos recursos provisionados ou usados, sem nenhum custo ou compromisso inicial.


| **Propriedades** | **Tabelas globais da mesma conta** | **Tabelas global de várias contas** | 
| --- | --- | --- | 
| Caso de uso principal | Resiliência multirregional para aplicações em uma única conta da AWS | Replicação em várias regiões e várias contas para aplicações pertencentes a equipes diferentes, unidades de negócios distintas ou limites de segurança robustos entre contas | 
| Modelo de conta | Todas as réplicas criadas e gerenciadas em uma conta da AWS | Réplicas criadas em várias contas da AWS na mesma implantação | 
| Propriedade de recursos | A tabela e todas as réplicas pertencem a uma única conta | Cada conta detém sua réplica local; o grupo de replicação abrange contas | 
| Versão compatível | Tabela globais versão 2.019.11.21 (atual) e versão 2017.11.29 (legada) | Tabelas globais versão 2019.11.21 (atual) | 
| Operações de ambiente de gerenciamento | Criar, modificar e excluir réplicas por meio da conta do proprietário da tabela | Operações do ambiente de gerenciamento distribuído: as contas entram ou saem do grupo de replicação | 
| Operações de planos de dados | Endpoints padrão do DynamoDB por região | Acesso ao plano de dados por conta/região; roteamento por meio do grupo de replicação | 
| Limite de segurança | Um único limite do IAM e do KMS | IAM, KMS, faturamento, CloudTrail e governança distintos por conta | 
| Mais adequado | Organizações em que a propriedade das tabelas é centralizada | Organizações com equipes federadas, limites de governança ou configurações de várias contas | 

**Topics**
+ [Modos de consistência](#GlobalTables.consistency-modes)
+ [Configurações da conta](#GlobalTables.account-configurations)
+ [Principais conceitos sobre tabelas globais](globaltables-CoreConcepts.md)
+ [Tabela global da mesma conta do DynamoDB](globaltables-SameAccount.md)
+ [Tabelas globais de várias contas do DynamoDB](globaltables-MultiAccount.md)
+ [Conceitos básicos sobre faturamento do Amazon DynamoDB para tabelas globais](global-tables-billing.md)
+ [Versões de tabelas globais do DynamoDB](V2globaltables_versions.md)
+ [Melhores práticas para tabelas globais](globaltables-bestpractices.md)

# Principais conceitos sobre tabelas globais
<a name="globaltables-CoreConcepts"></a>

As seções a seguir descrevem os conceitos e os comportamentos das tabelas globais no Amazon DynamoDB.

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

As *tabelas globais* são um recurso do DynamoDB que replica os dados da tabela em todas as regiões da AWS.

Uma *tabela-réplica* (ou réplica) é uma única tabela do DynamoDB que funciona como parte de uma tabela global. Uma tabela global consiste em duas ou mais tabelas de réplica em diferentes regiões da AWS. Cada tabela global só pode ter uma réplica por região da AWS. Todas as réplicas em uma tabela global compartilham o mesmo nome da tabela, esquema de chave primária e dados do item.

Quando uma aplicação grava dados em uma réplica em uma região, o DynamoDB replica automaticamente a gravação para as outras réplicas na tabela global. Para ter mais informações para começar a usar tabelas globais, consulte [Tutoriais: Criação de tabelas globais](V2globaltables.tutorial.md) ou [Tutoriais: criar de tabelas globais de várias contas](V2globaltables_MA.tutorial.md).

## Versões
<a name="globaltables-CoreConcepts.Versions"></a>

Há duas versões disponíveis das tabelas globais do DynamoDB: [Global Tables versão 2019.11.21 (atual)](GlobalTables.md) e [Global Tables versão 2017.11.29 (herdada)](globaltables.V1.md). É necessário usar a versão de tabelas globais 2019.11.21 (atual) sempre que possível. As informações nesta seção de documentação são para a versão 2019.11.21 (atual). Para ter mais informações sobre como determinar a versão de uma tabela global, consulte [Determinar a versão de uma tabela global](V2globaltables_versions.md#globaltables.DetermineVersion).

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

As tabelas globais ajudam a melhorar a continuidade de seus negócios, facilitando a implementação de uma arquitetura de alta disponibilidade multirregional. Se uma workload em uma única região da AWS se tornar prejudicada, você poderá transferir o tráfego do aplicativo para uma região diferente e executar leituras e gravações em uma tabela de réplica diferente na mesma tabela global.

Cada tabela de réplica em uma tabela global oferece a mesma durabilidade e disponibilidade de uma tabela do DynamoDB de região única. As tabelas globais oferecem um [Acordo de Serviço (SLA)](https://aws.amazon.com//dynamodb/sla/) com 99,999% de disponibilidade, em comparação com 99,99% das tabelas de região única.

## Teste de injeção de falhas
<a name="fault-injection-testing"></a>

As tabelas globais MREC e MRSC integram-se ao [Serviço de Injeção de Falhas da AWS](https://docs.aws.amazon.com/resilience-hub/latest/userguide/testing.html) (AWS FIS), um serviço totalmente gerenciado para executar experimentos de injeção de falhas controladas para melhorar a resiliência de uma aplicação. Por meio do AWS FIS, é possível:
+ Criar modelos de experimentos que definam cenários de falha específicos.
+ Injetar falhas para validar a resiliência da aplicação simulando o isolamento de região (isto é, pausando a replicação de e para uma réplica selecionada) para testar o tratamento de erros, os mecanismos de recuperação e o comportamento de mudança de tráfego em várias regiões quando uma região da AWS sofre interrupções.

Por exemplo, em uma tabela global com réplicas nas regiões Leste dos EUA (Norte da Virgínia), Leste dos EUA (Ohio) e Oeste dos EUA (Oregon), é possível executar um experimento na região Leste dos EUA (Ohio) para testar o isolamento de região lá e, ao mesmo tempo, continuar as operações normais na região Oeste dos EUA (Oregon). Esse teste controlado ajuda você a identificar e resolver possíveis problemas antes que eles afetem as workloads de produção. 

Consulte [Destinos da ação](https://docs.aws.amazon.com/fis/latest/userguide/action-sequence.html#action-targets) no *Guia do usuário do AWS FIS* para ver uma lista completa das ações permitidas pelo AWS FIS e da [conectividade entre regiões](https://docs.aws.amazon.com/fis/latest/userguide/cross-region-scenario.html) para pausar a replicação do DynamoDB entre regiões.

Para ter informações sobre as ações de tabelas globais do Amazon DynamoDB disponíveis no AWS FIS, consulte [Referência de ações de tabelas globais do DynamoDB](https://docs.aws.amazon.com/fis/latest/userguide/fis-actions-reference.html#dynamodb-actions-reference) no *Guia do usuário do AWS*.

Para começar a realizar experimentos de injeção de falhas, consulte [Planejar experimentos do AWS FIS](https://docs.aws.amazon.com/fis/latest/userguide/getting-started-planning.html) no “Guia do usuário do AWS FIS”.

**nota**  
Durante experimentos do AWS FIS no modo de consistência forte multirregional (MRSC), leituras finais consistentes são permitidas, mas atualizações de configuração de tabela, como alterar o modo de cobrança ou configurar o throughput da tabela, não são permitidas, de maneira semelhante ao modo de consistência final multirregional (MREC). Verifique a métrica [`FaultInjectionServiceInducedErrors`](metrics-dimensions.md#FaultInjectionServiceInducedErrors) do CloudWatch para ver detalhes adicionais sobre o código de erro.

## Vida útil (TTL)
<a name="global-tables-ttl"></a>

As tabelas globais configuradas para o MREC dão suporte à configuração da exclusão [Time To Live](TTL.md) (TTL). As configurações de TTL são sincronizadas automaticamente para todas as réplicas em uma tabela global. Quando o TTL exclui um item de uma réplica em uma região, a exclusão é replicada para todas as outras réplicas na tabela global. O TTL não consome capacidade de gravação, portanto, você não é cobrado pela exclusão TTL na região em que a exclusão ocorreu. No entanto, você é cobrado pela exclusão replicada em cada outra região com uma réplica na tabela global.

A replicação de exclusão TTL consome capacidade de gravação nas réplicas nas quais a exclusão está sendo replicada. As réplicas configuradas para capacidade provisionada podem limitar as solicitações de controle de utilização se a combinação de throughput de gravação e throughput de exclusão TTL for maior que a capacidade de gravação provisionada.

As tabelas globais configuradas para consistência forte multirregional (MRSC) não suportam a configuração da exclusão Time To Live (TTL).

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

As tabelas globais configuradas para consistência final multirregional (MREC) replicam as alterações lendo essas alterações de um [DynamoDB Stream](Streams.md) em uma tabela de réplica e aplicando essa alteração a todas as outras tabelas de réplica. Portanto, os streams são habilitados por padrão em todas as réplicas em uma tabela global do MREC e não podem ser desativados nessas réplicas. O processo de replicação do MREC pode combinar várias alterações em um curto período de tempo em uma única gravação replicada, resultando em cada fluxo de réplica contendo registros ligeiramente diferentes. Os registros de fluxos nas réplicas com MREC mantêm a ordem de todas as alterações no mesmo item, mas a ordem relativa das alterações em itens diferentes pode variar entre as réplicas.

Se você quiser escrever um aplicativo que processe registros do Streams para alterações que ocorreram em uma determinada região, mas não em outras em uma tabela global, você pode adicionar um atributo a cada item que define em qual região a alteração desse item ocorreu. Você pode usar esse atributo para filtrar os registros do Streams em busca de alterações que ocorreram em outras regiões, incluindo o uso de filtros de eventos do Lambda para invocar somente as funções do Lambda para alterações em uma região específica.

As tabelas globais configuradas para consistência forte multirregionais (MRSC) não usam o DynamoDB Streams para replicação, portanto, o Streams não é habilitado por padrão nas réplicas do MRSC. Você pode habilitar o Streams em uma réplica do MRSC. Os registros de streams nas réplicas do MRSC são idênticos para cada réplica, incluindo a ordenação dos registros do Stream.

## Transações
<a name="global-tables-transactions"></a>

Em uma tabela global configurada para MREC, as operações de transação ([https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) e [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html)) do DynamoDB são atômicas somente na região em que a operação foi invocada. As gravações transacionais não são replicadas como uma unidade em todas as regiões, o que significa que somente algumas das gravações em uma transação podem ser retornadas por operações de leitura em outras réplicas em um determinado momento.

Por exemplo, se você tiver uma tabela global com réplicas nas regiões Leste dos EUA (Ohio) e Oeste dos EUA (Oregon) e realizar uma operação `TransactWriteItems` na região Leste dos EUA (Ohio), poderá observar transações parcialmente concluídas na região Oeste dos EUA (Oregon) à medida que as alterações forem replicadas. As alterações só serão replicadas para outras regiões quando forem confirmadas na região de origem.

As tabelas globais configuradas para consistência forte multirregional (MRSC) não dão suporte a operações de transação e retornarão um erro se essas operações forem invocadas em uma réplica do MRSC.

## Throughput de leitura e gravação
<a name="globaltables-CoreConcepts.Throughput"></a>

### Modo provisionado
<a name="gt_throughput.provisioned"></a>

A replicação consome capacidade de gravação. As réplicas configuradas para capacidade provisionada podem controlar a utilização de solicitações se a soma do throughput de gravação de aplicação e do throughput de gravação de replicação ultrapassar a capacidade de gravação provisionada. Para tabelas globais que usam o modo provisionado, as configurações de ajuste de escala automático das capacidades de leitura e gravação são sincronizadas entre as réplicas.

É possível definir de forma independente as configurações de capacidade de leitura para cada réplica em uma tabela global usando o parâmetro [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ProvisionedThroughputOverride.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ProvisionedThroughputOverride.html) em nível de réplica. Por padrão, as alterações na capacidade de leitura provisionada são aplicadas a todas as réplicas na tabela global. Ao adicionar uma nova réplica a uma tabela global, a capacidade de leitura da tabela ou réplica de origem é usada como valor inicial, a menos que uma substituição em nível de réplica seja especificada explicitamente.

### Modo sob demanda
<a name="gt_throughput.on-demand"></a>

Para tabelas globais configuradas para o modo sob demanda, a capacidade de gravação é sincronizada automaticamente em todas as réplicas. O DynamoDB ajusta automaticamente a capacidade com base no tráfego, e não há configurações de capacidade de leitura ou gravação específicas da réplica para gerenciar.

## Monitorar tabelas globais
<a name="monitoring-global-tables"></a>

Tabelas globais configuradas para consistência final em várias regiões (MREC) publicam a métrica [`ReplicationLatency`](metrics-dimensions.md#ReplicationLatency) no CloudWatch. Essa métrica controla o tempo decorrido entre quando um item foi gravado em uma tabela-réplica e quando esse item aparece em outra réplica na tabela global. `ReplicationLatency` é expresso em milissegundos e é emitido para cada par de regiões de origem e destino em uma tabela global. 

Os valores típicos de `ReplicationLatency` dependem da distância entre as regiões da AWS escolhidas, bem como de outras variáveis como tipo de workload e throughput. Por exemplo, uma réplica de origem na região Oeste dos EUA (N. da Califórnia) (us-west-1) tem uma `ReplicationLatency` menor para a região Oeste dos EUA (Oregon) (us-west-2) em comparação com a região África (Cidade do Cabo) (af-south-1).

Um valor elevado para `ReplicationLatency` pode indicar que as atualizações de uma réplica não se propagaram para outras tabelas-réplica em tempo hábil. Nesse caso, você pode redirecionar temporariamente as atividades de leitura e gravação da aplicação para outra região da AWS.

As tabelas globais configuradas para consistência forte multirregional (MRSC) não publicam uma métrica de `ReplicationLatency`.

## Considerações para gerenciar tabelas globais
<a name="management-considerations"></a>

Você não pode excluir uma tabela usada para adicionar uma nova réplica de tabela global até que tenham decorrido 24 horas desde que a nova réplica foi criada.

Se você desabilitar uma região da AWS que contém réplicas de tabelas globais, essas réplicas serão convertidas permanentemente em tabelas de região única 20 horas após a desativação da região.

# Tabela global da mesma conta do DynamoDB
<a name="globaltables-SameAccount"></a>

As tabelas globais da mesma conta replicam automaticamente os dados da tabela do DynamoDB em várias regiões da AWS em uma única conta da AWS. As tabelas globais da mesma conta são o modelo mais simples para executar aplicações multirregionais porque todas as réplicas compartilham o mesmo modelo de limite de conta, propriedade e permissões. Quando você escolhe as regiões da AWS para suas tabelas-réplica, as tabelas globais lidam com todas as replicações automaticamente. As tabelas globais estão disponíveis em todas as regiões onde o DynamoDB está disponível.

As tabelas globais da mesma conta oferecem os seguintes benefícios:
+ Replicação automática dos dados da tabela do DynamoDB em todas as regiões da AWS de sua escolha para posicionar os dados mais perto dos usuários
+ Maior disponibilidade de aplicações durante isolamento ou degradação regional.
+ Utilização da resolução de conflitos integrada para que você possa se concentrar na lógica de negócios da sua aplicação.
+ Possibilidade de escolher entre [Consistência final multirregional (MREC)](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes.mrec) ou [Consistência forte multirregional (MRSC)](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes.mrsc) ao criar uma tabela global da mesma conta.

**Topics**
+ [Como funcionam as tabelas globais do DynamoDB](V2globaltables_HowItWorks.md)
+ [Tutoriais: Criação de tabelas globais](V2globaltables.tutorial.md)
+ [Segurança de tabelas globais do DynamoDB](globaltables-security.md)

# Como funcionam as tabelas globais do DynamoDB
<a name="V2globaltables_HowItWorks"></a>

As seções a seguir descrevem os conceitos e os comportamentos das tabelas globais no Amazon DynamoDB.

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

*As tabelas globais* são um recurso do DynamoDB que replica os dados da tabela em todas as regiões da AWS. 

Uma *tabela-réplica* (ou réplica) é uma única tabela do DynamoDB que funciona como parte de uma tabela global. Uma tabela global consiste em duas ou mais tabelas de réplica em diferentes regiões da AWS. Cada tabela global só pode ter uma réplica por região da AWS. Todas as réplicas em uma tabela global compartilham o mesmo nome da tabela, esquema de chave primária e dados do item.

Quando uma aplicação grava dados em uma réplica em uma região, o DynamoDB replica automaticamente a gravação para as outras réplicas na tabela global. Para obter mais informações sobre conceitos básicos de tabelas globais, consulte [Tutoriais: Criação de tabelas globais](V2globaltables.tutorial.md).

## Versões
<a name="V2globaltables_HowItWorks.versions"></a>

Há duas versões disponíveis das tabelas globais do DynamoDB: versão 2019.11.21 (atual) e [versão 2017.11.29 (legada)](globaltables.V1.md). Você deve usar a versão 2019.11.21 (atual) sempre que possível. As informações nesta seção de documentação são para a versão 2019.11.21 (atual). Para obter mais informações, consulte [Determinar a versão de uma tabela global](V2globaltables_versions.md#globaltables.DetermineVersion).

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

As tabelas globais ajudam a melhorar a continuidade de seus negócios, facilitando a implementação de uma arquitetura de alta disponibilidade multirregional. Se uma workload em uma única região da AWS se tornar prejudicada, você poderá transferir o tráfego do aplicativo para uma região diferente e executar leituras e gravações em uma tabela de réplica diferente na mesma tabela global.

Cada tabela de réplica em uma tabela global oferece a mesma durabilidade e disponibilidade de uma tabela do DynamoDB de região única. As tabelas globais oferecem um [Acordo de Serviço (SLA)](https://aws.amazon.com//dynamodb/sla/) com 99,999% de disponibilidade, em comparação com 99,99% das tabelas de região única.

## Modos de consistência
<a name="V2globaltables_HowItWorks.consistency-modes"></a>

Ao criar uma tabela global, você pode configurar o modo de consistência. As tabelas globais permitem dois modos de consistência: consistência final multirregional (MREC) e consistência forte multirregional (MRSC).

Se você não especificar um modo de consistência ao criar uma tabela global, ela usará como padrão a consistência final multirregional (MREC). Uma tabela global não pode conter réplicas configuradas com modos de consistência diferentes. Não é possível alterar o modo de consistência de uma tabela global depois da criação.

### Consistência final multirregional (MREC)
<a name="V2globaltables_HowItWorks.consistency-modes.mrec"></a>

A consistência final multirregional (MREC) é o modo de consistência padrão para tabelas globais. As alterações feitas em um item em uma réplica da tabela global MREC são replicadas de forma assíncrona em todas as outras réplicas, normalmente em um segundo ou menos. No caso improvável de uma réplica em uma tabela global do MREC ficar isolada ou danificada, todos os dados ainda não replicados para outras regiões serão replicados quando a réplica ficar íntegra.

Se o mesmo item for modificado em várias regiões simultaneamente, o DynamoDB resolverá o conflito usando a modificação com o registro de data e hora interno mais recente por item, conhecido como método de resolução de conflitos do tipo “último escritor vence”. Um item acabará por convergir em todas as réplicas para a versão criada pela última gravação.

[Operações de leitura altamente consistentes](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html#DDB-GetItem-request-ConsistentRead) retornam a versão mais recente de um item se ele tiver sido atualizado pela última vez na região onde a leitura ocorreu, mas podem retornar dados obsoletos se o item tiver sido atualizado pela última vez em uma região diferente. As gravações condicionais avaliam a expressão da condição em relação à versão do item na região.

Você cria uma tabela global MREC adicionando uma réplica a uma tabela existente do DynamoDB. Adicionar uma réplica não afeta o desempenho das tabelas existentes do DynamoDB de região única ou nas réplicas de tabelas globais existentes. Você pode adicionar réplicas a uma tabela global do MREC para expandir o número de regiões em que os dados são replicados ou remover réplicas de uma tabela global do MREC se elas não forem mais necessárias. Uma tabela global do MREC pode ter uma réplica em qualquer região onde o DynamoDB esteja disponível e pode ter quantas réplicas houver regiões na partição [AWS](https://docs.aws.amazon.com/whitepapers/latest/aws-fault-isolation-boundaries/partitions.html).

### Consistência forte multirregional (MRSC)
<a name="V2globaltables_HowItWorks.consistency-modes.mrsc"></a>

Você pode configurar o modo de consistência forte multirregional (MRSC) ao criar uma tabela global. As alterações de item em uma réplica da tabela global do MRSC são replicadas de forma síncrona em pelo menos uma outra região antes que a operação de gravação retorne uma resposta bem-sucedida. Operações de leitura altamente consistentes em qualquer réplica do MRSC sempre retornam a versão mais recente de um item. As gravações condicionais sempre avaliam a expressão da condição em relação à versão mais recente de um item.

Uma tabela global do MRSC deve ser implantada em exatamente três regiões. Você pode configurar uma tabela global MRSC com três réplicas ou duas réplicas e uma testemunha. Uma testemunha é um componente de uma tabela global com MRSC que contém dados gravados em réplicas da tabela global e pode ser usado opcionalmente no lugar de uma réplica completa, ao mesmo tempo em que é compatível com a arquitetura de disponibilidade de MRSC. Você não pode realizar operações de leitura ou gravação em uma testemunha. Uma testemunha está localizada em uma região diferente das duas réplicas. Ao criar uma tabela global do MRSC, você escolhe as regiões para suas réplicas e para a implantação da testemunha no momento da criação da tabela MRSC. Você pode determinar se e em qual região uma tabela global do MRSC tem uma testemunha configurada a partir da saída da API [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html). A testemunha pertence e é gerenciada pelo DynamoDB, e a testemunha não aparecerá na sua conta da AWS na região em que está configurada.

As tabelas globais com MRSC estão disponíveis nos seguintes conjuntos de regiões: dos EUA [Leste dos EUA (Norte da Virgínia), Leste dos EUA (Ohio), Oeste dos EUA (Oregon)], da UE [Europa (Irlanda), Europa (Londres), Europa (Paris), Europa (Frankfurt)] e da Ásia-Pacífico [Ásia-Pacífico (Tóquio), Ásia-Pacífico (Seul) e Ásia-Pacífico (Osaka)]. As tabelas globais do MRSC não podem abranger conjuntos de regiões (por exemplo, uma tabela global do MRSC não pode conter réplicas dos conjuntos de regiões dos EUA e da UE).

Você cria uma tabela global MRSC adicionando uma réplica e uma testemunha ou duas réplicas a uma tabela existente do DynamoDB que não contém dados. Ao converter uma tabela de região única existente em uma tabela global com MRSC, é necessário garantir que a tabela esteja vazia. Não é possível converter uma tabela de região única em uma tabela global com MRSC que já contenha itens. Nenhum dado deve ser gravado na tabela durante o processo de conversão. Você não pode adicionar réplicas adicionais a uma tabela global MRSC existente. Não é possível excluir uma única réplica ou testemunha de uma tabela global do MRSC. Você pode excluir duas réplicas ou excluir uma réplica e uma testemunha de uma tabela global do MRSC, convertendo a réplica restante em uma tabela do DynamoDB de região única.

Uma operação de gravação falha com um erro `ReplicatedWriteConflictException` quando ela tenta modificar um item que já está sendo modificado em outra região. As gravações que falharem, exibindo o erro `ReplicatedWriteConflictException`, poderão ser repetidas e terão êxito se o item não estiver mais sendo modificado em outra região.

As seguintes considerações se aplicam às tabelas globais do MRSC:
+ Tempo de vida (TTL) não é aceito em tabelas globais do MRSC.
+ Índices secundários locais (LSIs) não são aceitos em tabelas globais do MRSC.
+ As informações do CloudWatch Contributor Insights são relatadas somente para a região em que uma operação ocorreu.

## Escolher um modo de consistência
<a name="V2globaltables_HowItWorks.choosing-consistency-mode"></a>

O principal critério para escolher um modo de consistência multirregional é se seu aplicativo prioriza gravações de menor latência e leituras altamente consistentes ou prioriza uma consistência global forte.

As tabelas globais MREC terão latências de gravação e de leitura altamente consistente mais baixas em comparação às tabelas globais MRSC. As tabelas globais com MREC têm um objetivo de ponto de recuperação (RPO) igual ao atraso de replicação entre as réplicas, geralmente de alguns segundos, dependendo das regiões da réplica.

Você deve usar o modo MREC quando:
+ A aplicação pode tolerar dados obsoletos exibidos por operações de leitura altamente consistente se esses dados tiverem sido atualizados em outra região.
+ Você prioriza latências de gravação e de leitura altamente consistente mais baixas em relação à consistência de leitura multirregional.
+ Sua estratégia de alta disponibilidade multirregional pode tolerar um RPO maior que zero.

As tabelas globais MRSC terão latências de gravação e leitura altamente consistente mais altas em comparação às tabelas globais MREC. As tabelas globais do MRSC oferecem suporte a um objetivo de ponto de recuperação (RPO) de zero.

É necessário usar o modo MRSC quando:
+ Você precisa de leituras altamente consistentes em várias regiões.
+ Você prioriza a consistência global de leitura em detrimento da menor latência de gravação.
+ Sua estratégia de alta disponibilidade multirregional exige um RPO igual a zero.

## Monitorar tabelas globais
<a name="monitoring-global-tables"></a>

Tabelas globais configuradas para consistência final em várias regiões (MREC) publicam a métrica [`ReplicationLatency`](metrics-dimensions.md#ReplicationLatency) no CloudWatch. Essa métrica controla o tempo decorrido entre quando um item foi gravado em uma tabela-réplica e quando esse item aparece em outra réplica na tabela global. `ReplicationLatency` é expresso em milissegundos e é emitido para cada par de regiões de origem e destino em uma tabela global. 

Os valores típicos de `ReplicationLatency` dependem da distância entre as regiões da AWS escolhidas, bem como de outras variáveis como tipo de workload e throughput. Por exemplo, uma réplica de origem na região Oeste dos EUA (N. da Califórnia) (us-west-1) tem uma `ReplicationLatency` menor para a região Oeste dos EUA (Oregon) (us-west-2) em comparação com a região África (Cidade do Cabo) (af-south-1).

Um valor elevado para `ReplicationLatency` pode indicar que as atualizações de uma réplica não se propagaram para outras tabelas-réplica em tempo hábil. Nesse caso, você pode redirecionar temporariamente as atividades de leitura e gravação da aplicação para outra região da AWS.

As tabelas globais configuradas para consistência forte multirregional (MRSC) não publicam uma métrica de `ReplicationLatency`.

## Teste de injeção de falhas
<a name="fault-injection-testing"></a>

As tabelas globais MREC e MRSC integram-se ao [Serviço de Injeção de Falhas da AWS](https://docs.aws.amazon.com/resilience-hub/latest/userguide/testing.html) (AWS FIS), um serviço totalmente gerenciado para executar experimentos de injeção de falhas controladas para melhorar a resiliência de uma aplicação. Por meio do AWS FIS, é possível:
+ Criar modelos de experimentos que definam cenários de falha específicos.
+ Injetar falhas para validar a resiliência da aplicação simulando o isolamento de região (isto é, pausando a replicação de e para uma réplica selecionada) para testar o tratamento de erros, os mecanismos de recuperação e o comportamento de mudança de tráfego em várias regiões quando uma região da AWS sofre interrupções.

Por exemplo, em uma tabela global com réplicas nas regiões Leste dos EUA (Norte da Virgínia), Leste dos EUA (Ohio) e Oeste dos EUA (Oregon), é possível executar um experimento na região Leste dos EUA (Ohio) para testar o isolamento de região lá e, ao mesmo tempo, continuar as operações normais na região Oeste dos EUA (Oregon). Esse teste controlado ajuda você a identificar e resolver possíveis problemas antes que eles afetem as workloads de produção. 

Consulte [Destinos da ação](https://docs.aws.amazon.com/fis/latest/userguide/action-sequence.html#action-targets) no *Guia do usuário do AWS FIS* para ver uma lista completa das ações permitidas pelo AWS FIS e da [conectividade entre regiões](https://docs.aws.amazon.com/fis/latest/userguide/cross-region-scenario.html) para pausar a replicação do DynamoDB entre regiões.

Para ter informações sobre as ações de tabelas globais do Amazon DynamoDB disponíveis no AWS FIS, consulte [Referência de ações de tabelas globais do DynamoDB](https://docs.aws.amazon.com/fis/latest/userguide/fis-actions-reference.html#dynamodb-actions-reference) no *Guia do usuário do AWS*.

Para começar a realizar experimentos de injeção de falhas, consulte [Planejar experimentos do AWS FIS](https://docs.aws.amazon.com/fis/latest/userguide/getting-started-planning.html) no “Guia do usuário do AWS FIS”.

**nota**  
Durante experimentos do AWS FIS no modo de consistência forte multirregional (MRSC), leituras finais consistentes são permitidas, mas atualizações de configuração de tabela, como alterar o modo de cobrança ou configurar o throughput da tabela, não são permitidas, de maneira semelhante ao modo de consistência final multirregional (MREC). Verifique a métrica [`FaultInjectionServiceInducedErrors`](metrics-dimensions.md#FaultInjectionServiceInducedErrors) do CloudWatch para ver detalhes adicionais sobre o código de erro.

## Vida útil (TTL)
<a name="global-tables-ttl"></a>

As tabelas globais configuradas para o MREC dão suporte à configuração da exclusão [Time To Live](TTL.md) (TTL). As configurações de TTL são sincronizadas automaticamente para todas as réplicas em uma tabela global. Quando o TTL exclui um item de uma réplica em uma região, a exclusão é replicada para todas as outras réplicas na tabela global. O TTL não consome capacidade de gravação, portanto, você não é cobrado pela exclusão TTL na região em que a exclusão ocorreu. No entanto, você é cobrado pela exclusão replicada em cada outra região com uma réplica na tabela global.

A replicação de exclusão TTL consome capacidade de gravação nas réplicas nas quais a exclusão está sendo replicada. As réplicas configuradas para capacidade provisionada podem limitar as solicitações de controle de utilização se a combinação de throughput de gravação e throughput de exclusão TTL for maior que a capacidade de gravação provisionada.

As tabelas globais configuradas para consistência forte multirregional (MRSC) não suportam a configuração da exclusão Time To Live (TTL).

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

As tabelas globais configuradas para consistência final multirregional (MREC) replicam as alterações lendo essas alterações de um [DynamoDB Stream](Streams.md) em uma tabela de réplica e aplicando essa alteração a todas as outras tabelas de réplica. Portanto, os streams são habilitados por padrão em todas as réplicas em uma tabela global do MREC e não podem ser desativados nessas réplicas. O processo de replicação do MREC pode combinar várias alterações em um curto período de tempo em uma única gravação replicada, resultando em cada fluxo de réplica contendo registros ligeiramente diferentes. Os registros de streams em réplicas do MREC são sempre ordenados por item, mas a ordenação entre itens pode ser diferente entre as réplicas.

As tabelas globais configuradas para consistência forte multirregionais (MRSC) não usam o DynamoDB Streams para replicação, portanto, o Streams não é habilitado por padrão nas réplicas do MRSC. Você pode habilitar o Streams em uma réplica do MRSC. Os registros de streams nas réplicas do MRSC são idênticos para cada réplica, incluindo a ordenação dos registros do Stream.

Se você quiser escrever um aplicativo que processe registros do Streams para alterações que ocorreram em uma determinada região, mas não em outras em uma tabela global, você pode adicionar um atributo a cada item que define em qual região a alteração desse item ocorreu. Você pode usar esse atributo para filtrar os registros do Streams em busca de alterações que ocorreram em outras regiões, incluindo o uso de filtros de eventos do Lambda para invocar somente as funções do Lambda para alterações em uma região específica.

## Transações
<a name="global-tables-transactions"></a>

Em uma tabela global configurada para MREC, as operações de transação ([https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) e [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html)) do DynamoDB são atômicas somente na região em que a operação foi invocada. As gravações transacionais não são replicadas como uma unidade em todas as regiões, o que significa que somente algumas das gravações em uma transação podem ser retornadas por operações de leitura em outras réplicas em um determinado momento.

Por exemplo, se você tiver uma tabela global com réplicas nas regiões Leste dos EUA (Ohio) e Oeste dos EUA (Oregon) e realizar uma operação `TransactWriteItems` na região Leste dos EUA (Ohio), poderá observar transações parcialmente concluídas na região Oeste dos EUA (Oregon) à medida que as alterações forem replicadas. As alterações só serão replicadas para outras regiões quando forem confirmadas na região de origem.

As tabelas globais configuradas para consistência forte multirregional (MRSC) não dão suporte a operações de transação e retornarão um erro se essas operações forem invocadas em uma réplica do MRSC.

## Throughput de leitura e gravação
<a name="V2globaltables_HowItWorks.Throughput"></a>

### Modo provisionado
<a name="gt_throughput.provisioned"></a>

A replicação consome capacidade de gravação. As réplicas configuradas para capacidade provisionada podem controlar a utilização de solicitações se a soma do throughput de gravação de aplicação e do throughput de gravação de replicação ultrapassar a capacidade de gravação provisionada. Para tabelas globais que usam o modo provisionado, as configurações de ajuste de escala automático das capacidades de leitura e gravação são sincronizadas entre as réplicas.

É possível definir de forma independente as configurações de capacidade de leitura para cada réplica em uma tabela global usando o parâmetro [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ProvisionedThroughputOverride.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ProvisionedThroughputOverride.html) em nível de réplica. Por padrão, as alterações na capacidade de leitura provisionada são aplicadas a todas as réplicas na tabela global. Ao adicionar uma nova réplica a uma tabela global, a capacidade de leitura da tabela ou réplica de origem é usada como valor inicial, a menos que uma substituição em nível de réplica seja especificada explicitamente.

### Modo sob demanda
<a name="gt_throughput.on-demand"></a>

Para tabelas globais configuradas para o modo sob demanda, a capacidade de gravação é sincronizada automaticamente em todas as réplicas. O DynamoDB ajusta automaticamente a capacidade com base no tráfego, e não há configurações de capacidade de leitura ou gravação específicas da réplica para gerenciar.

## Sincronização das configurações
<a name="V2globaltables_HowItWorks.setting-synchronization"></a>

As configurações nas tabelas globais do DynamoDB são parâmetros de configuração que controlam vários aspectos do comportamento e da replicação da tabela. Essas configurações são gerenciadas por meio das APIs do ambiente de gerenciamento do DynamoDB e podem ser configuradas ao criar ou modificar tabelas globais. As tabelas globais sincronizam automaticamente determinadas configurações em todas as réplicas para manter a consistência e, ao mesmo tempo, permitir flexibilidade para otimizações específicas da região. Entender quais configurações são sincronizadas e como elas se comportam ajuda você a configurar sua tabela global de forma eficaz. As configurações se dividem em três categorias principais com base em como elas são sincronizadas entre as réplicas.

As configurações a seguir são sempre sincronizadas entre as réplicas em uma tabela global:
+ Modo de capacidade (capacidade provisionada ou sob demanda)
+ Capacidade de gravação provisionada da tabela
+ Ajuste de escala automático de gravação da tabela
+ Definição de atributo do esquema de chaves
+ Definição do Índice Secundário Global (GSI)
+ Capacidade de gravação provisionada do GSI
+ Ajuste de escala automático de gravação do GSI
+ Tipo de criptografia do lado do servidor (SSE)
+ Definição de streams no modo MREC
+ Vida útil (TTL)
+ Throughput a quente
+ Throughput máximo de gravação sob demanda

As configurações a seguir são sincronizadas entre as réplicas, mas podem ser substituídas por réplica:
+ Capacidade de leitura provisionada da tabela
+ Ajuste de escala automático de leitura de tabela
+ Capacidade de leitura provisionadas do GSI
+ Ajuste de escala automático de leitura do GSI
+ Classe de tabela
+ Throughput máximo de leitura sob demanda

**nota**  
Os valores de configuração substituíveis são alterados se a configuração for modificada em qualquer outra réplica. Como exemplo, você tem uma tabela global do MREC com réplicas nas regiões Leste dos EUA (Norte da Virgínia) e Oeste dos EUA (Oregon). A réplica do Leste dos EUA (Norte da Virgínia) tem o throughput de leitura provisionada definido para 200 RCUs. A réplica no Oeste dos EUA (Oregon) tem a substituição do throughput de leitura provisionada definido para 100 RCUs. Se você atualizar a configuração de throughput de leitura provisionada na réplica do Leste dos EUA (Norte da Virgínia) de 200 RCUs para 300 RCUs, o novo valor da taxa de transferência de leitura provisionada também será aplicado à réplica no Oeste dos EUA (Oregon). Isso altera a configuração de throughput de leitura provisionada para a réplica do Oeste dos EUA (Oregon) do valor substituído de 100 RCUs para o novo valor de 300 RCUs.

As configurações a seguir nunca são sincronizadas entre as réplicas:
+ Proteção contra exclusão
+ Recuperação para um ponto no tempo
+ Tags
+ Habilitação da tabela do CloudWatch Contributor Insights
+ Habilitação do GSI do CloudWatch Contributor Insights
+ Definição do Kinesis Data Streams
+ Políticas de recursos
+ Definição de streams no modo MRSC

Todas as outras configurações não são sincronizadas entre as réplicas.

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

As gravações em réplicas de tabelas globais ignoram o DynamoDB Accelerator (DAX), atualizando o DynamoDB diretamente. Como resultado, os caches do DAX podem ficar obsoletos, pois as gravações não estão atualizando o cache do DAX. Os caches do DAX configurados para réplicas de tabelas globais só serão atualizados quando o TTL do cache expirar.

## Considerações para gerenciar tabelas globais
<a name="management-considerations"></a>

Você não pode excluir uma tabela usada para adicionar uma nova réplica de tabela global até que tenham decorrido 24 horas desde que a nova réplica foi criada.

Se você desabilitar uma região da AWS que contém réplicas de tabelas globais, essas réplicas serão convertidas permanentemente em tabelas de região única 20 horas após a desativação da região.

# Tutoriais: Criação de tabelas globais
<a name="V2globaltables.tutorial"></a>

Esta seção fornece instruções passo a passo para criar tabelas globais do DynamoDB configuradas para o modo de consistência preferido. Escolha entre os modos consistência final multirregional (MREC) ou consistência forte multirregional (MRSC) com base nos requisitos do seu aplicativo.

As tabelas globais MREC fornecem menor latência de gravação com consistência final entre Regiões da AWS. As tabelas globais MRSC fornecem leituras altamente consistentes em todas as regiões com latências de gravação ligeiramente maiores do que as do MREC. Escolha o modo de consistência que melhor atenda às necessidades de consistência, latência e disponibilidade dos dados do seu aplicativo.

**Topics**
+ [Criação de uma tabela global configurada para MREC](#V2creategt_mrec)
+ [Criação de uma tabela global configurada para MRSC](#create-gt-mrsc)

## Criação de uma tabela global configurada para MREC
<a name="V2creategt_mrec"></a>

Esta seção mostra como criar uma tabela global com o modo consistência final multirregional (MREC). MREC é o modo de consistência padrão para tabelas globais e fornece gravações de baixa latência com replicação assíncrona em Regiões da AWS. As alterações feitas em um item em uma região geralmente são replicadas em todas as outras regiões em um segundo. Isso torna o MREC ideal para aplicativos que priorizam a baixa latência de gravação e podem tolerar breves períodos em que diferentes regiões podem retornar versões de dados ligeiramente diferentes.

Você pode criar tabelas globais MREC com réplicas em qualquer região da AWS que o DynamoDB esteja disponível e adicionar ou remover réplicas a qualquer momento. Os exemplos a seguir mostram como criar uma tabela global MREC com réplicas em várias regiões.

### Criação de uma tabela global MREC usando o DynamoDB Console
<a name="mrec-console"></a>

Siga estas etapas para criar uma tabela global usando o Console de gerenciamento da AWS. O exemplo a seguir cria uma tabela global com tabelas-réplica nos Estados Unidos e na Europa.

1. Faça login no Console de gerenciamento da AWS e abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/).

1. Para este exemplo, escolha **Leste dos EUA (Ohio)** no seletor de região na barra de navegação.

1. No painel de navegação, no lado esquerdo do console, selecione **Tables** (Tabelas).

1. Selecione **Create Table** (Criar tabela).

1. Na página **Criar tabela**:

   1. Em **Table name** (Nome da tabela), insira **Music**.

   1. Em **Partition key**, (Chave de partição), insira **Artist**.

   1. Em **Chave de classificação**, insira **SongTitle**.

   1. Mantenha o restante das configurações padrão e escolha **Criar tabela**.

      Essa nova tabela serve como a primeira tabela de réplica em uma nova tabela global. Ela é o protótipo das outras tabelas-réplica que serão adicionadas posteriormente.

1. Depois que a tabela ficar ativa:

   1. Selecione a tabela **Music** (Música) na lista de tabelas.

   1. Selecione a guia **Global Tables (Tabelas globais)**.

   1. Escolha **Create replica (Criar réplica)**.

1. Na lista suspensa **Regiões de replicação disponíveis**, escolha **US West (Oregon) us-west-2** (Oeste dos EUA [Oregon], us-west-2).

   O console garante que não exista uma tabela com o mesmo nome na região selecionada. Se existir uma tabela com o mesmo nome, será necessário excluir a tabela existente para criar outra tabela-réplica nessa região.

1. Escolha **Create replica (Criar réplica)**. Isso inicia o processo de criação da tabela na região Oeste dos EUA (Oregon), us-west-2.

   A guia **Tabelas globais** da tabela **Music** (e de qualquer outra tabela-réplica) mostra que a tabela foi replicada em várias regiões.

1. Adicione outra região repetindo as etapas anteriores, mas escolha **Europa (Frankfurt) eu-central-1** como região.

1. Como testar a replicação:

   1. Continue usando o Console de gerenciamento da AWS na região Leste dos EUA (Ohio).

   1. Escolha **Explore table items** (Explorar itens da tabela).

   1. Selecione **Create Item** (Criar item).

   1. Insira **item\$11** para **Artist (Artista)** e **Song Value 1** para **SongTitle (Título da música)**.

   1. Selecione **Create Item** (Criar item).

1. Verifique a replicação mudando para outras regiões:

   1. No seletor de regiões no canto superior direito, escolha **Europa (Frankfurt)**.

   1. Verifique se a tabela **Music (Música)** contém o item que você criou.

   1. Repita a verificação para **Oeste dos EUA (Oregon)**.

### Criar uma tabela global MREC usando a AWS CLI ou Java
<a name="mrec-cli-java"></a>

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

O exemplo de código a seguir mostra como gerenciar tabelas globais do DynamoDB com consistência final de replicação mutirregional (MREC).
+ Crie uma tabela com replicação mutirregional (MREC).
+ Insira e obtenha itens de tabelas-réplica.
+ Remova as réplicas uma por uma.
+ Exclua a tabela para fazer uma limpeza.

**AWS CLI com script Bash**  
Crie uma tabela com replicação mutirregional.  

```
# 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
```
Descreva a tabela multirregional.  

```
# 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}}'
```
Insira itens em uma tabela-réplica.  

```
# 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
```
Obtenha itens de tabelas-réplica.  

```
# 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
```
Remova as réplicas.  

```
# 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
```
Exclua a tabela para fazer uma limpeza.  

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

echo "Global table demonstration complete."
```
+ Consulte detalhes da API nos tópicos a seguir na *Referência de comandos da 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 ]

O exemplo de código a seguir mostra como criar e gerenciar tabelas globais do DynamoDB com réplicas entre várias regiões.
+ Crie uma tabela com um índice secundário global e DynamoDB Streams.
+ Adicione réplicas em diferentes regiões para criar uma tabela global.
+ Remova réplicas de uma tabela global.
+ Adicione itens de teste para verificar a replicação entre regiões.
+ Descreva a configuração da tabela global e o status da réplica.

**SDK para Java 2.x**  
Crie uma tabela com um índice secundário global e DynamoDB Streams usando 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;
        }
    }
```
Aguarde até que uma tabela se torne ativa usando 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;
        }
    }
```
Adicione uma réplica para criar ou estender uma tabela global usando 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;
        }
    }
```
Remova uma réplica de uma tabela global usando 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;
        }
    }
```
Adicione itens de teste para verificar a replicação usando 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;
        }
    }
```
Descreva a configuração e as réplicas da tabela global usando 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;
        }
    }
```
Exemplo completo de operações de tabela global usando 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;
            }
        }
    }
```
+ Para obter detalhes da API, consulte os tópicos a seguir na *Referência da 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)

------

## Criação de uma tabela global configurada para MRSC
<a name="create-gt-mrsc"></a>

Esta seção mostra como criar uma tabela global de consistência forte multirregional (MRSC). As tabelas globais do MRSC replicam de forma síncrona as alterações de itens em todas as regiões, garantindo que as operações de leitura altamente consistentes em qualquer réplica sempre retornem a versão mais recente de um item. Ao converter uma tabela de região única em uma tabela global com MRSC, você deve garantir que a tabela esteja vazia. Não é possível converter uma tabela de região única em uma tabela global com MRSC que já contenha itens. Nenhum dado deve ser gravado na tabela durante o processo de conversão.

Você pode configurar uma tabela global MRSC com três réplicas ou duas réplicas e uma testemunha. Ao criar uma tabela global do MRSC, você escolhe as regiões em que as réplicas e uma testemunha opcional são implantadas. O exemplo a seguir cria uma tabela global MRSC com réplicas nas regiões Leste dos EUA (Norte da Virgínia) e Leste dos EUA (Ohio), com uma testemunha na região Oeste dos EUA (Oregon).

**nota**  
Antes de criar uma tabela global, verifique se os limites de throughput da cota de serviço são consistentes em todas as regiões de destino, pois isso é necessário para criar uma tabela global. Para ter mais informações sobre os limites globais de throughput de tabelas, consulte as [cotas para tabelas globais](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ServiceQuotas.html#gt-limits-throughput).

### Criação de uma tabela global MRSC usando o DynamoDB Console
<a name="mrsc_console"></a>

Siga estas etapas para criar uma tabela global MRSC usando o Console de gerenciamento da AWS.

1. Faça login no Console de gerenciamento da AWS e abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/).

1. No seletor de regiões na barra de navegação, escolha a região onde as tabelas globais com MRSC são [aceitas](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes), por exemplo, **us-east-2**.

1. No painel de navegação, selecione **Tabelas**.

1. Escolha **Criar tabela**.

1. Na página **Criar tabela**:

   1. Em **Table name** (Nome da tabela), insira **Music**.

   1. Para a **Chave de partição**, insira **Artist** e mantenha o tipo **String** padrão.

   1. Em **Chave de classificação**, insira **SongTitle** e mantenha o tipo **String** padrão.

   1. Mantenha o restante das configurações padrão e escolha **Criar tabela**.

      Essa nova tabela serve como a primeira tabela de réplica em uma nova tabela global. Ela é o protótipo das outras tabelas-réplica que serão adicionadas posteriormente.

1. Aguarde até que a tabela fique ativa e, em seguida, selecione-a na lista de tabelas.

1. Selecione a guia **Tabelas globais** e escolha **Criar réplica**.

1. Na página **Criar réplica**:

   1. Em **Consistência multirregional**, escolha **Consistência forte**.

   1. Para a **Região de Replicação 1**, escolha **US East (N. Virginia) us-east-1**.

   1. Para a **Região de Replicação 2**, escolha **US West (Oregon) us-west-2**.

   1. Marque **Configurar como Testemunha** para a região Oeste dos EUA (Oregon).

   1. Escolha **Criar réplicas**.

1. Aguarde a conclusão do processo de criação da réplica e da testemunha. O status da tabela será exibido como **Ativo** quando a tabela estiver pronta para uso.

### Criar uma tabela global MRSC usando a AWS CLI ou Java
<a name="mrsc-cli-java"></a>

Antes de começar, verifique se a entidade principal do IAM tem as permissões necessárias para criar uma tabela global com MRSC com uma região testemunha.

O seguinte exemplo de política do IAM permite que você crie uma tabela do DynamoDB (`MusicTable`) no Leste dos EUA (Ohio) com uma réplica no Leste dos EUA (Norte da Virgínia) e uma região testemunha no Oeste dos EUA (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"
                }
            }
        }
    ]
}
```

------

O exemplo de código a seguir mostra como criar e gerenciar tabelas globais do DynamoDB com consistência forte multirregional (MRSC).
+ Crie uma tabela com consistência forte multirregional.
+ Verifique a configuração de MRSC e o status da réplica.
+ Teste a consistência forte entre regiões com leituras imediatas.
+ Faça gravações condicionais com garantia de MRSC.
+ Limpe os recursos da tabela global com MRSC.

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

**AWS CLI com script Bash**  
Crie uma tabela com consistência forte multirregional.  

```
# 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
```
Verifique a configuração de MRSC e o status da réplica.  

```
# 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}}'
```
Teste a consistência forte com leituras imediatas entre regiões.  

```
# 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
```
Faça gravações condicionais com garantia de 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
```
Limpe os recursos da tabela global com 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
```
+ Consulte detalhes da API nos tópicos a seguir na *Referência de comandos da 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 para Java 2.x**  
Crie uma tabela regional pronta para conversão MRSC usando 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();
        }
    }
```
Converta uma tabela regional para MRSC com réplicas e testemunhas usando 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();
        }
    }
```
Descreva uma configuração de tabela global do MRSC usando 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();
        }
    }
```
Adicione itens de teste para verificar a forte consistência do MRSC usando 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();
        }
    }
```
Leia itens com leituras consistentes de réplicas do MRSC usando 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();
        }
    }
```
Faça atualizações condicionais com garantias de MRSC usando 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();
        }
    }
```
Aguarde até que as réplicas e testemunhas do MRSC se tornem ativas usando 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;
        }
    }
```
Limpe as réplicas e testemunhas do MRSC usando 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();
        }
    }
```
Demonstração completa do fluxo de trabalho do MRSC usando 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;
        }
    }
```
+ Para obter detalhes da API, consulte os tópicos a seguir na *Referência da 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)

------

# Segurança de tabelas globais do DynamoDB
<a name="globaltables-security"></a>

As réplicas de tabelas globais são tabelas do DynamoDB, então você usa os mesmos métodos para controlar o acesso às réplicas que usa para tabelas de região única, incluindo políticas de identidade e políticas baseadas em recursos do AWS Identity and Access Management (IAM).

Este tópico aborda como proteger tabelas globais do DynamoDB usando permissões do IAM e criptografia AWS Key Management Service (AWS KMS). Você aprenderá mais sobre os perfis vinculados a serviços (SLR) que permitem a replicação e o ajuste de escala automático entre regiões, as permissões do IAM necessárias para criar, atualizar e excluir tabelas globais e as diferenças entre as tabelas com consistência final multirregional (MREC) e com consistência forte multirregional (MRSC). Você também aprenderá mais sobre chaves de criptografia do AWS KMS para gerenciar a replicação entre regiões com segurança.

## Perfis vinculados a serviços para tabelas globais
<a name="globaltables-slr"></a>

As tabelas globais do DynamoDB dependem de perfis vinculados a serviços (SLRs) para gerenciar a replicação entre regiões e os recursos de ajuste de escala automático.

Você precisa configurar esses perfis somente uma vez por conta da AWS. Depois de criados, os mesmos perfis atendem a todas as tabelas globais da sua conta. Para ter mais informações sobre perfis vinculados ao serviço, consulte [Criar um perfil vinculado ao serviço](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html) no *Guia do usuário do IAM*.

### Função vinculada ao serviço de replicação
<a name="globaltables-replication-slr"></a>

O Amazon DynamoDB cria automaticamente o perfil vinculado a serviços `AWSServiceRoleForDynamoDBReplication` (SLR) quando você cria sua primeira tabela global. Esse perfil gerencia a replicação entre regiões para você.

Ao aplicar políticas baseadas em recursos às réplicas, não negue nenhuma das permissões definidas em `AWSServiceRoleForDynamoDBReplicationPolicy` à entidade principal SLR, pois isso interromperá a replicação. Se você negar as permissões SLR necessárias, a replicação de e para as réplicas afetadas será interrompida e o status da tabela de réplicas mudará para `REPLICATION_NOT_AUTHORIZED`.
+ No caso de tabelas globais de consistência eventual multirregional (MREC), se uma réplica permanecer no estado `REPLICATION_NOT_AUTHORIZED` por mais de 20 horas, ela será convertida irreversivelmente em uma tabela do DynamoDB de região única.
+ Para tabelas globais de consistência forte multirregional (MRSC), negar as permissões necessárias resulta em `AccessDeniedException` para operações de gravação e leitura altamente consistente. Se uma réplica permanecer no estado `REPLICATION_NOT_AUTHORIZED` por mais de sete dias, a réplica ficará permanentemente inacessível e as operações de gravação e leitura altamente consistentes continuarão falhando com um erro. Algumas operações de gerenciamento, como a exclusão de réplicas, serão bem-sucedidas.

### Função vinculada a serviço do IAM para ajuste de escala automático
<a name="globaltables-autoscaling-slr"></a>

Quando você configura uma tabela global para o modo de capacidade provisionada, também deve configurar o ajuste de escala automático para ela. O ajuste de escala automático do DynamoDB usa o serviço AWS Application Auto Scaling para ajustar dinamicamente a capacidade de throughput em suas réplicas de tabela global. O serviço Application Auto Scaling cria um perfil vinculado ao serviço (SLR) chamado [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). Esse perfil vinculado a serviços é criado automaticamente em sua conta da AWS quando você configura o ajuste de escala automático para uma tabela do DynamoDB. Ele permite que o Application Auto Scaling gerencie a capacidade provisionada da tabela e crie alarmes do CloudWatch. 

 Quando você aplicar políticas baseadas em recursos às réplicas, não negue nenhuma das permissões definidas em [https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSApplicationAutoscalingDynamoDBTablePolicy.html](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSApplicationAutoscalingDynamoDBTablePolicy.html) à entidade principal de SLR do Application Auto Scaling, pois isso interromperá a funcionalidade de ajuste de escala automático.

### Exemplo de políticas do IAM para perfis vinculados a serviços
<a name="globaltables-example-slr"></a>

Uma política do IAM com a condição a seguir não afeta as permissões necessárias para a SLR de replicação e a SLR de ajuste de escala automático da AWS do DynamoDB. Essa condição pode ser adicionada a políticas amplamente restritivas para evitar a interrupção involuntária da replicação ou do ajuste de escala automático:

#### Excluir as permissões SLR necessárias das políticas de negação
<a name="example-exclude-slr-policy"></a>

O exemplo a seguir mostra como excluir as entidades principais do perfil vinculado a serviços das instruções de negação:

```
"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"
        ]
    }
}
```

## Como as tabelas globais usam o IAM da AWS
<a name="globaltables-iam"></a>

As seções a seguir descrevem as permissões necessárias para diferentes operações de tabela global e contêm exemplos de políticas para ajudar você a configurar o acesso apropriado para seus usuários e aplicações.

**nota**  
Todas as permissões descritas devem ser aplicadas ao ARN do recurso de tabela específico nas regiões afetadas. O ARN do recurso de tabela segue o formato `arn:aws:dynamodb:region:account-id:table/table-name`, no qual você precisa especificar os valores reais de região, ID da conta e nome da tabela.

**Topics**
+ [Criar tabelas globais e adicionar réplicas](#globaltables-creation-iam)
+ [Atualizar tabelas globais](#globaltables-update-iam)
+ [Excluir tabelas globais e remover réplicas](#globaltables-delete-iam)

### Criar tabelas globais e adicionar réplicas
<a name="globaltables-creation-iam"></a>

As tabelas globais do DynamoDB comportam dois modos de consistência: consistência eventual multirregional (MREC) e consistência forte multirregional (MRSC). As tabelas globais MREC podem ter várias réplicas em qualquer número de regiões e fornecer consistência eventual. As tabelas globais MRSC exigem exatamente três regiões (três réplicas ou duas réplicas e uma testemunha) e fornecem consistência forte com objetivo de ponto de recuperação (RPO) zero.

As permissões necessárias para criar tabelas globais dependem de você criar uma tabela global com ou sem uma testemunha.

#### Permissões para criar tabelas globais
<a name="globaltables-creation-iam-all-types"></a>

As permissões a seguir são necessárias tanto para a criação de tabelas globais iniciais quanto para adicionar réplicas posteriormente. Essas permissões se aplicam às tabelas globais de consistência final multirregional (MREC) e consistência forte multirregional (MRSC).
+ As tabelas globais exigem replicação entre regiões, que o DynamoDB gerencia por meio do perfil vinculado a serviços (SLR) [`AWSServiceRoleForDynamoDBReplication`](#globaltables-replication-slr). A permissão a seguir permite que o DynamoDB crie esse perfil automaticamente quando você cria uma tabela global pela primeira vez:
  + `iam:CreateServiceLinkedRole`
+ Para criar uma tabela global ou adicionar uma réplica usando a API [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html), é necessário ter a seguinte permissão no recurso da tabela de origem:
  + `dynamodb:UpdateTable`
+ É necessário ter as seguintes permissões no recurso de tabela nas regiões para que as réplicas sejam adicionadas:
  + `dynamodb:CreateTable`
  + `dynamodb:CreateTableReplica`
  + `dynamodb:Query`
  + `dynamodb:Scan`
  + `dynamodb:UpdateItem`
  + `dynamodb:PutItem`
  + `dynamodb:GetItem`
  + `dynamodb:DeleteItem`
  + `dynamodb:BatchWriteItem`

#### Permissões adicionais para tabelas globais MRSC usando uma testemunha
<a name="globaltables-creation-iam-witness"></a>

Ao criar uma tabela global de consistência forte multirregional (MRSC) com uma região testemunha, você deve ter a seguinte permissão no recurso de tabela em todas as regiões participantes (incluindo as regiões de réplica e a região testemunha):
+ `dynamodb:CreateGlobalTableWitness`

#### Exemplos de política do IAM para criar tabelas globais
<a name="globaltables-creation-iam-example"></a>

##### Criar uma tabela global MREC ou MRSC em três regiões
<a name="globaltables-creation-iam-example-three-regions"></a>

A política baseada em identidade a seguir permite criar uma tabela global MREC ou MRSC chamada “usuários” em três regiões, incluindo a criação do perfil vinculado a serviços de replicação do DynamoDB necessário.

------
#### [ 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"
      ]
    }
  ]
}
```

------

##### Restringir a criação de tabelas globais MREC ou MRSC a regiões específicas
<a name="globaltables-creation-iam-example-restrict-regions"></a>

A política baseada em identidade a seguir permite criar réplicas de tabelas globais do DynamoDB em regiões específicas usando a chave de condição [aws:RequestedRegion](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-requestedregion), incluindo a criação do perfil vinculado a serviços de replicação do DynamoDB necessário.

------
#### [ 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"
      ]
    }
  ]
}
```

------

##### Criar uma tabela global MRSC com testemunha
<a name="globaltables-creation-iam-example-witness"></a>

A política baseada em identidade a seguir permite criar uma tabela global do DynamoDB MRSC chamada “users” com réplicas em us-east-1 e us-east-2 e uma testemunha em us-west-2, incluindo a criação do perfil vinculado a serviços de replicação do DynamoDB necessário.

------
#### [ 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"
      ]
    }
  ]
}
```

------

##### Restringir a criação de testemunhas MRSC a regiões específicas
<a name="globaltables-creation-iam-example-restrict-witness-regions"></a>

A política baseada em identidade permite criar uma tabela global MRSC com réplicas restrita a regiões específicas usando a chave de condição [aws:RequestedRegion](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-requestedregion) e criação de testemunhas sem restrições em todas as regiões, incluindo a criação do perfil vinculado a serviços de replicação do DynamoDB necessário.

------
#### [ 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"
      ]
    }
  ]
}
```

------

### Atualizar tabelas globais
<a name="globaltables-update-iam"></a>

Para modificar as configurações de réplica de uma tabela global existente usando a API [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html), é preciso ter a seguinte permissão no recurso de tabela na região em que você está fazendo a chamada de API:
+ `dynamodb:UpdateTable`

Além disso, você pode atualizar outras configurações da tabela global, como políticas de ajuste de escala automático e configurações de tempo de vida. As seguintes permissões são necessárias para essas operações adicionais de atualização:
+ Para atualizar uma política de ajuste de escala automático da réplica com a API [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTableReplicaAutoScaling.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTableReplicaAutoScaling.html), é necessário ter as seguintes permissões no recurso de tabela em todas as regiões que contêm réplicas:
  + `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`
+ Para atualizar as configurações de tempo de vida com a API [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTimeToLive.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTimeToLive.html), você deve ter a seguinte permissão no recurso de tabela em todas as regiões que contêm réplicas:
  + `dynamodb:UpdateTimeToLive`

  Observe que o tempo de vida (TTL) é compatível somente com tabelas globais configuradas com consistência eventual multirregional (MREC). Para acessar mais informações sobre como tabelas globais funcionam com TTL, consulte [Como funcionam as tabelas globais do DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/V2globaltables_HowItWorks.html).

### Excluir tabelas globais e remover réplicas
<a name="globaltables-delete-iam"></a>

Para excluir uma tabela global, você deve remover todas as réplicas. As permissões necessárias para essa operação variam dependendo se você está excluindo uma tabela global com ou sem uma região testemunha.

#### Permissões para excluir tabelas globais e remover réplicas
<a name="globaltables-delete-iam-all-types"></a>

As permissões a seguir são necessárias tanto para remover réplicas individuais quanto para excluir completamente as tabelas globais. A exclusão de uma configuração de tabela global só remove o relacionamento de replicação entre tabelas em diferentes regiões. Ela não exclui a tabela subjacente do DynamoDB na última região restante. A tabela na última região continua existindo como uma tabela padrão do DynamoDB com os mesmos dados e configurações. Essas permissões se aplicam às tabelas globais de consistência final multirregional (MREC) e consistência forte multirregional (MRSC). 
+ Para remover réplicas de uma tabela global usando a API [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html), você precisa da seguinte permissão no recurso de tabela na região em que está fazendo a chamada de API:
  + `dynamodb:UpdateTable`
+ Você precisa das seguintes permissões no recurso de tabela em cada região em que você está removendo uma réplica:
  + `dynamodb:DeleteTable`
  + `dynamodb:DeleteTableReplica`

#### Permissões adicionais para tabelas globais MRSC usando uma testemunha
<a name="globaltables-delete-iam-witness"></a>

Ao excluir uma tabela global de consistência forte multirregional (MRSC) com uma testemunha, você deve ter a seguinte permissão no recurso de tabela em todas as regiões participantes (incluindo as regiões de réplica e a região testemunha):
+ `dynamodb:DeleteGlobalTableWitness`

#### Exemplos de política do IAM para excluir réplicas de uma tabela global
<a name="globaltables-delete-iam-example"></a>

##### Excluir réplicas de tabelas globais
<a name="globaltables-delete-replicas-iam-example"></a>

Essa política baseada em identidade permite que você exclua uma tabela global do DynamoDB chamada “users” e suas respectivas réplicas em três regiões:

------
#### [ 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"
      ]
    }
  ]
}
```

------

##### Excluir uma tabela global MRSC com uma testemunha
<a name="globaltables-delete-witness-iam-example"></a>

Essa política baseada em identidade permite que você exclua a réplica e a testemunha de uma tabela global MRSC chamada “users”:

------
#### [ 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"
      ]
    }
  ]
}
```

------

## Como as tabelas globais usam AWS KMS
<a name="globaltables-kms"></a>

Como todas as tabelas do DynamoDB, as réplicas de tabelas globais sempre criptografam dados em repouso usando chaves de criptografia armazenadas no AWS Key Management Service (AWS KMS).

Todas as réplicas em uma tabela global devem ser configuradas com o mesmo tipo de chave KMS (chave própria da AWS, chave gerenciada da AWS ou chave gerenciada pelo cliente).

**Importante**  
O DynamoDB exige acesso à chave de criptografia da réplica para excluir uma réplica. Se você quiser desativar ou excluir uma chave gerenciada pelo cliente usada para criptografar uma réplica porque você está excluindo a réplica, primeiro exclua a réplica, aguarde até que o status da tabela em uma das réplicas restantes mude para `ACTIVE`, então desative ou exclua a chave.

Para uma tabela global configurada para consistência final multirregional (MREC), se você desativar ou revogar o acesso do DynamoDB a uma chave gerenciada pelo cliente usada para criptografar uma réplica, a replicação de e para a réplica será interrompida e o status da réplica mudará para `INACCESSIBLE_ENCRYPTION_CREDENTIALS`. Se uma réplica em uma tabela global do MREC permanecer no estado `INACCESSIBLE_ENCRYPTION_CREDENTIALS` por mais de 20 horas, a réplica será convertida irreversivelmente em uma tabela do DynamoDB de região única.

Para uma tabela global configurada para consistência forte multirregional (MRSC), se você desativar ou revogar o acesso do DynamoDB a uma chave gerenciada pelo cliente usada para criptografar uma réplica, a replicação de e para a réplica será interrompida, as tentativas de realizar gravações ou leituras altamente consistentes na réplica retornarão um erro, e o status da réplica mudará para `INACCESSIBLE_ENCRYPTION_CREDENTIALS`. Se uma réplica em uma tabela global do MRSC permanecer no estado `INACCESSIBLE_ENCRYPTION_CREDENTIALS` por mais de sete dias, dependendo das permissões específicas revogadas, a réplica será arquivada ou ficará permanentemente inacessível.

# Tabelas globais de várias contas do DynamoDB
<a name="globaltables-MultiAccount"></a>

As tabelas globais de várias contas replicam automaticamente os dados da tabela do DynamoDB em várias regiões da AWS e várias contas da AWS para melhorar a resiliência, isolar workloads em nível de conta e aplicar controles distintos de segurança e governança. Cada tabela-réplica reside em uma conta da AWS distinta, permitindo o isolamento de falhas em nível de região e de conta. Também é possível alinhar as réplicas à sua estrutura organizacional da AWS. As tabelas globais de várias contas oferecem benefícios adicionais de isolamento, governança e segurança em comparação às tabelas globais da mesma conta.

As tabelas globais de várias contas oferecem os seguintes benefícios:
+ Replicação automática de tabelas do DynamoDB nas regiões da AWS escolhidas por você.
+ Fortalecimento da segurança e da governança ao replicar dados entre contas com políticas, barreiras de proteção e limites de conformidade distintos.
+ Aprimoramento da resiliência operacional e do isolamento de falhas em nível de conta ao posicionar réplicas em contas AWS separadas.
+ Alinhamento das workloads por unidade de negócios ou propriedade usando uma estratégia de várias contas.
+ Simplificação da atribuição de custos, faturando cada réplica na respectiva conta da AWS.

Para ter mais informações, consulte [Benefícios do uso de várias contas da AWS](https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/benefits-of-using-multiple-aws-accounts.html). Se suas workloads não precisarem de replicação em várias contas ou se quiser simplificar o gerenciamento de réplicas com substituições locais, você pode continuar usando tabelas globais da mesma conta.

É possível configurar tabelas globais de várias contas com [Consistência final multirregional (MREC)](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes.mrec). Não é possível usar tabelas globais configuradas para [Consistência forte multirregional (MRSC)](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes.mrsc) no modelo de várias contas.

**Topics**
+ [Como funcionam as tabelas globais do DynamoDB](V2globaltables_MA_HowItWorks.md)
+ [Tutoriais: criar de tabelas globais de várias contas](V2globaltables_MA.tutorial.md)
+ [Segurança de tabelas globais do DynamoDB](globaltables_MA_security.md)

# Como funcionam as tabelas globais do DynamoDB
<a name="V2globaltables_MA_HowItWorks"></a>

As tabelas globais de várias contas estendem os recursos totalmente gerenciados, multirregionais, sem servidor e multiativos das tabelas globais do DynamoDB para abranger várias contas da AWS. As tabelas globais de várias contas replicam dados entre regiões e contas da AWS, oferecendo a mesma funcionalidade ativa-ativa das tabelas globais da mesma conta. Quando você grava em qualquer réplica, o DynamoDB replica os dados em todas as outras réplicas.

As principais diferenças em relação às tabelas globais da mesma conta incluem:
+ É possível usar a replicação multirregional com tabelas globais com consistência final multirregional (MREC).
+ Só é possível adicionar réplicas começando com uma tabela de região única. Não é possível converter uma tabela global existente da mesma conta em uma configuração de várias contas. Para migrar e criar uma tabela global de várias contas, primeiro é necessário excluir as réplicas existentes para retornar a uma tabela de região única.
+ Cada réplica deve residir em uma conta da AWS separada. Para uma tabela global de várias contas com *N* réplicas, é necessário ter *N* contas.
+ Por padrão, as tabelas globais de várias contas usam configurações de tabela unificadas em todas as réplicas. Todas as réplicas compartilham automaticamente a mesma configuração (como modo de throughput e TTL) e, diferentemente das tabelas globais da mesma conta, essas configurações não podem ser substituídas por réplicas.
+ Os clientes devem fornecer permissões de replicação à entidade principal do serviço de tabelas globais do DynamoDB em suas políticas de recursos.

As tabelas globais de várias contas usam a mesma tecnologia de replicação subjacente das tabelas globais da mesma conta. As configurações da tabela são replicadas automaticamente em todas as réplicas regionais e os clientes não podem substituí-las por réplicas nem personalizá-las. Isso garante uma configuração consistente e um comportamento previsível em várias contas da AWS que compartilham a mesma tabela global.

As configurações nas tabelas globais do DynamoDB definem como uma tabela se comporta e como os dados são replicados nas regiões. Essas configurações são definidas por meio de APIs do ambiente de gerenciamento do DynamoDB durante a criação da tabela ou ao adicionar uma nova réplica regional.

Ao criar uma tabela global de várias contas, os clientes devem definir `GlobalTableSettingsReplicationMode = ENABLED` para cada réplica regional. Isso garante que as alterações de configuração feitas em uma região se propaguem automaticamente para todas as outras regiões que compartilham a tabela global.

É possível habilitar a replicação das configurações após a criação da tabela. Isso é adequado para o cenário em que uma tabela é criada originalmente como uma tabela regional e depois atualizada para uma tabela global de várias contas.

**Configurações sincronizadas**

As seguintes configurações são sempre sincronizadas entre as réplicas em uma tabela global de várias contas:

**nota**  
Diferentemente das tabelas globais da mesma conta, as tabelas globais de várias contas não permitem substituições por região para essas configurações. A única exceção é que as substituições de políticas de ajuste de escala automático de leitura (tabelas e GSIs) são permitidas, pois são recursos externos separados.
+ Modo de capacidade (capacidade provisionada ou sob demanda)
+ Capacidade provisionada de leitura e gravação da tabela
+ Ajuste de escala automático de leitura e gravação da tabela
+ Definição do índice secundário local (LSI)
+ Definição do Índice Secundário Global (GSI)
+ Capacidade provisionada de leitura e gravação do GSI
+ Ajuste de escala automático de leitura e gravação do GSI
+ Definição de streams no modo MREC
+ Vida útil (TTL)
+ Throughput a quente
+ Throughput máximo sob demanda de leitura e gravação

**Configurações não sincronizadas**

As configurações a seguir não são sincronizadas entre as réplicas e devem ser definidas de forma independente para cada tabela-réplica em cada região.
+ Classe de tabela
+ Tipo de criptografia do lado do servidor (SSE)
+ Recuperação para um ponto no tempo
+ ID da chave do KMS da criptografia do lado do servidor (SSE)
+ Proteção contra exclusão
+ Kinesis Data Streams (KDSD)
+ Tags
+ Política de recursos
+ Tabela Cloudwatch-Contributor Insights (CCI)
+ GSI Cloudwatch-Contributor Insights (CCI)

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

Tabelas globais configuradas para consistência final em várias regiões (MREC) publicam a métrica [`ReplicationLatency`](metrics-dimensions.md#ReplicationLatency) no CloudWatch. Essa métrica controla o tempo decorrido entre quando um item foi gravado em uma tabela-réplica e quando esse item aparece em outra réplica na tabela global. `ReplicationLatency` é expresso em milissegundos e é emitido para cada par de regiões de origem e destino em uma tabela global.

Os valores típicos de `ReplicationLatency` dependem da distância entre as regiões da AWS escolhidas, bem como de outras variáveis como tipo de workload e throughput. Por exemplo, uma réplica de origem na região Oeste dos EUA (N. da Califórnia) (us-west-1) tem uma `ReplicationLatency` menor para a região Oeste dos EUA (Oregon) (us-west-2) em comparação com a região África (Cidade do Cabo) (af-south-1).

Um valor elevado para `ReplicationLatency` pode indicar que as atualizações de uma réplica não se propagaram para outras tabelas-réplica em tempo hábil. Nesse caso, você pode redirecionar temporariamente as atividades de leitura e gravação da aplicação para outra região da AWS.

**Lidar com problemas de latência de replicação em tabelas globais de várias contas**

Se `ReplicationLatency` exceder três horas devido a problemas causados pelo cliente em uma tabela-réplica, o DynamoDB enviará uma notificação solicitando que o cliente resolva o problema subjacente. Os problemas comuns causados pelo cliente que podem impedir a replicação incluem:
+ Remover as permissões necessárias da política de recursos da tabela-réplica.
+ Optar por não aderir a uma região da AWS que hospede uma réplica da tabela global de várias contas.
+ Negar as permissões da chave do AWS KMS da tabela necessárias para descriptografar dados.

Dentro de três horas, o DynamoDB enviará uma notificação inicial de alta latência de replicação, seguida de uma segunda notificação após vinte horas se o problema continuar sem solução. Se o problema não for corrigido dentro do período exigido, o DynamoDB desassociará automaticamente a réplica da tabela global. Depois, a réplica afetada será convertida em uma tabela regional.

# Tutoriais: criar de tabelas globais de várias contas
<a name="V2globaltables_MA.tutorial"></a>

Esta seção contém instruções passo a passo para criar tabelas globais do DynamoDB que abrangem várias contas da AWS.

## Criar uma tabela global de várias contas usando o console do DynamoDB
<a name="create-ma-gt-console"></a>

Siga estas etapas para criar uma tabela global de várias contas usando o Console de gerenciamento da AWS. O exemplo a seguir cria uma tabela global com tabelas-réplica nos Estados Unidos.

1. Faça login no Console de gerenciamento da AWS e abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/) para a primeira conta (por exemplo, *111122223333*).

1. Para este exemplo, escolha **Leste dos EUA (Ohio)** no seletor de região na barra de navegação.

1. No painel de navegação, no lado esquerdo do console, selecione **Tables** (Tabelas).

1. Selecione **Create Table** (Criar tabela).

1. Na página **Criar tabela**:

   1. Em **Table name** (Nome da tabela), insira **MusicTable**.

   1. Em **Partition key**, (Chave de partição), insira **Artist**.

   1. Em **Chave de classificação**, insira **SongTitle**.

   1. Mantenha o restante das configurações padrão e escolha **Criar tabela**.

1. Adicione a seguinte política de recursos à tabela.

------
#### [ 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. Essa nova tabela serve como a primeira tabela de réplica em uma nova tabela global. Ela é o protótipo das outras tabelas-réplica que serão adicionadas posteriormente.

1. Aguarde a tabela se tornar **ativa**. Para a tabela recém-criada, na guia **Tabelas globais**, acesse **Replicação de configurações** e clique em **Habilitar**.

1. Saia dessa conta (aqui, *111122223333*).

1. Faça login no Console de gerenciamento da AWS e abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/) para a segunda conta (por exemplo, *444455556666*).

1. Para este exemplo, escolha **Leste dos EUA (Norte da Virgínia)** no seletor de região na barra de navegação.

1. O console garante que não exista uma tabela com o mesmo nome na região selecionada. Se existir uma tabela com o mesmo nome, será necessário excluir a tabela existente para criar outra tabela-réplica nessa região.

1. No menu suspenso próximo a **Criar tabela**, escolha **Criar de outra conta**

1. Na página **Criar tabela de outra conta**:

   1. Adicione **arn:aws:dynamodb:us-east-2:*111122223333*:table/MusicTable** como ARN da tabela de origem.

   1. Em **ARNs das réplicas da tabela**, adicione novamente o ARN **arn:aws:dynamodb:us-east-2:*111122223333*:table/MusicTable** da tabela de origem. Se várias réplicas já existirem como parte de uma tabela global de várias contas, será necessário adicionar todas as réplicas existentes a ReplicaTableARN.

   1. Mantenha o restante das configurações padrão e escolha **Enviar**.

1. A guia **Tabelas globais** da tabela “Music” (e de qualquer outra tabela-réplica) mostra que a tabela foi replicada em várias regiões.

1. Como testar a replicação:

   1. É possível usar qualquer uma das regiões em que exista uma réplica para essa tabela.

   1. Escolha **Explore table items** (Explorar itens da tabela).

   1. Selecione **Create Item** (Criar item).

   1. Insira **item\$11** para **Artist (Artista)** e **Song Value 1** para **SongTitle (Título da música)**.

   1. Selecione **Create Item** (Criar item).

   1. Verifique a replicação mudando para outras regiões:

   1. Verifique se a tabela Music (Música) contém o item que você criou.

## Criar uma tabela global de várias contas usando a AWS CLI
<a name="ma-gt-cli"></a>

Os exemplos a seguir mostram como criar uma tabela global de várias contas usando a AWS CLI. Esses exemplos demonstram o fluxo de trabalho completo para configurar a replicação entre contas.

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

Use os comandos da AWS CLI a seguir para criar uma tabela global de várias contas com replicação entre contas.

```
# 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
```

------

# Segurança de tabelas globais do DynamoDB
<a name="globaltables_MA_security"></a>

As réplicas de tabelas globais são tabelas do DynamoDB, então você usa os mesmos métodos para controlar o acesso às réplicas que usa para tabelas de região única, incluindo políticas de identidade e políticas baseadas em recursos do AWS Identity and Access Management (IAM). Este tópico aborda como proteger tabelas globais de várias contas do DynamoDB usando permissões do IAM e a criptografia do AWS Key Management Service (AWS KMS). Você aprenderá mais sobre políticas baseadas em recursos e perfis vinculados ao serviço (SLR) que permitem a replicação e o ajuste de escala automático entre contas e entre regiões, bem como sobre as permissões do IAM necessárias para criar, atualizar e excluir tabelas globais, para ter tabelas com consistência final multirregional (MREC). Você também aprenderá mais sobre chaves de criptografia do AWS KMS para gerenciar a replicação entre regiões com segurança.

Este tópico contém informações detalhadas sobre as políticas e permissões baseadas em recursos necessárias para estabelecer a replicação de tabelas entre contas e entre regiões. Compreender esse modelo de segurança é fundamental para clientes que precisam implementar soluções seguras de replicação de dados entre contas.

## Autorização de replicação à entidade principal do serviço
<a name="globaltables_MA_service_principal"></a>

As tabelas globais de várias contas do DynamoDB usam uma abordagem de autorização distinta porque a replicação é realizada entre os limites da conta. Isso é feito usando a entidade principal do serviço de replicação do DynamoDB: `replication.dynamodb.amazonaws.com`. Cada conta participante deve dar permissão explícita a essa entidade principal na política de recursos da tabela-réplica, concedendo a ela permissões que podem se restringir a réplicas específicas de acordo com as condições de contexto da origem em chaves como `aws:SourceAccount`, `aws:SourceArn` etc. Para ver detalhes, consulte [Chaves de condição globais da AWS](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html). As permissões são bidirecionais, o que significa que todas as réplicas devem conceder permissões explicitamente umas às outras para que a replicação seja estabelecida em qualquer par específico de réplicas.

As seguintes permissões de entidade principal de serviço são essenciais para a replicação entre contas:
+ `dynamodb:ReadDataForReplication` concede permissão para ler dados para fins de replicação. Esta permissão possibilita que as alterações em uma réplica sejam lidas e propagadas para outras réplicas.
+ `dynamodb:WriteDataForReplication` permite a gravação de dados replicados nas tabelas de destino. Esta permissão possibilita que as alterações sejam sincronizadas em todas as réplicas na tabela global.
+ `dynamodb:ReplicateSettings` permite a sincronização das configurações da tabela entre as réplicas, oferecendo uma configuração consistente em todas as tabelas participantes.

Cada réplica deve conceder as permissões acima a todas as outras réplicas e a si mesma; isto é, as condições de contexto da origem devem incluir o conjunto completo de réplicas que compõe a tabela global. Essas permissões são verificadas para cada nova réplica quando ela é adicionada a uma tabela global de várias contas. Esse processo verifica se as operações de replicação são realizadas somente pelo serviço autorizado do DynamoDB e apenas entre as tabelas pretendidas.

## Perfis vinculados ao serviço para tabelas globais de várias contas
<a name="globaltables_MA_service_linked_roles"></a>

As tabelas globais de várias contas do DynamoDB replicam as configurações em todas as réplicas para que cada réplica seja configurada de forma idêntica com um throughput consistente e ofereça uma experiência de failover contínua. A replicação das configurações é controlada por meio da permissão `ReplicateSettings` da entidade principal do serviço, mas também dependemos de perfis vinculados ao serviço (SLRs) para gerenciar determinados recursos de replicação e ajuste de escala automático entre contas e entre regiões. É necessário configurar esses perfis somente uma vez por conta da AWS. Depois de criados, os mesmos perfis atendem a todas as tabelas globais da sua conta. Para ter mais informações sobre perfis vinculados ao serviço, consulte [Criar um perfil vinculado ao serviço](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create-service-linked-role.html) no Guia do usuário do IAM.

### Perfil vinculado ao serviço de gerenciamento de configurações
<a name="globaltables_MA_settings_management_slr"></a>

O Amazon DynamoDB cria automaticamente o perfil vinculado ao serviço (SLR) AWSServiceRoleForDynamoDBGlobalTableSettingsManagement quando a primeira réplica de tabela global de várias contas é criada na conta. Esse perfil gerencia a replicação de configurações entre contas e entre regiões para você.

Ao aplicar políticas baseadas em recursos às réplicas, não negue nenhuma das permissões definidas em `AWSServiceRoleForDynamoDBGlobalTableSettingsManagement` à entidade principal do SLR, pois isso pode interferir no gerenciamento de configurações e prejudicar a replicação se o throughput não corresponder entre as réplicas ou os GSIs. Se você negar as permissões de SLR necessárias, a replicação entre as réplicas afetadas será interrompida e o status da tabela-réplica mudará para `REPLICATION_NOT_AUTHORIZED`. No caso de tabelas globais de várias contas, se uma réplica permanecer no estado `REPLICATION_NOT_AUTHORIZED` por mais de vinte horas, ela será convertida irreversivelmente em uma tabela do DynamoDB de região única. O SLR tem as seguintes permissões:
+ `application-autoscaling:DeleteScalingPolicy`
+ `application-autoscaling:DescribeScalableTargets`
+ `application-autoscaling:DescribeScalingPolicies`
+ `application-autoscaling:DeregisterScalableTarget`
+ `application-autoscaling:PutScalingPolicy`
+ `application-autoscaling:RegisterScalableTarget`

### Função vinculada a serviço do IAM para ajuste de escala automático
<a name="globaltables_MA_autoscaling_slr"></a>

Quando você configura uma tabela global para o modo de capacidade provisionada, também deve configurar o ajuste de escala automático para ela. O ajuste de escala automático do DynamoDB usa o serviço AWS Application Auto Scaling para ajustar dinamicamente a capacidade de throughput em suas réplicas de tabela global. O serviço Application Auto Scaling cria um perfil vinculado ao serviço (SLR) chamado [AWSServiceRoleForApplicationAutoScaling\$1DynamoDBTable](https://docs.aws.amazon.com/autoscaling/application/userguide/application-auto-scaling-service-linked-roles.html). Esse perfil vinculado ao serviço é criado automaticamente em sua conta da AWS quando você configura o ajuste de escala automático para uma tabela do DynamoDB. Isso permite que o Application Auto Scaling gerencie a capacidade provisionada da tabela e crie alarmes do CloudWatch.

Ao aplicar políticas baseadas em recursos às réplicas, verifique se você não negou nenhuma permissão definida em [AWSApplicationAutoscalingDynamoDBTablePolicy](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSApplicationAutoscalingDynamoDBTablePolicy.html) à entidade principal de SLR do Application Auto Scaling, pois isso interromperá a funcionalidade de ajuste de escala automático.

## Como as tabelas globais usam o IAM da AWS
<a name="globaltables_MA_iam"></a>

As seções a seguir descrevem as permissões necessárias para diferentes operações de tabela global e contêm exemplos de políticas para ajudar você a configurar o acesso apropriado para seus usuários e aplicações.

**nota**  
Todas as permissões descritas devem ser aplicadas ao ARN do recurso de tabela específico nas regiões afetadas. O ARN do recurso de tabela segue o formato `arn:aws:dynamodb:region:account-id:table/table-name`, no qual você precisa especificar os valores reais de região, ID da conta e nome da tabela.

Estes são os tópicos detalhados que abordamos nas seções abaixo:
+ Criar tabelas globais de várias contas e adicionar réplicas
+ Atualizar uma tabela global de várias contas
+ Excluir tabelas globais e remover réplicas

### Criar tabelas globais e adicionar réplicas
<a name="globaltables_MA_creating"></a>

#### Permissões para criar tabelas globais
<a name="globaltables_MA_creating_permissions"></a>

Quando uma nova réplica é adicionada a uma tabela regional para formar uma tabela global de várias contas ou a uma tabela global de várias contas existente, a entidade principal do IAM que executa a ação deve ser autorizada por todos os membros existentes. Todos os membros existentes precisam conceder a seguinte permissão em sua política de tabela para que a inclusão da réplica seja bem-sucedida:
+ `dynamodb:AssociateTableReplica`: esta permissão possibilita que as tabelas sejam unidas em uma configuração de tabela global. Ela é fundamental para o estabelecimento inicial da relação de replicação.

Esse controle preciso permite que somente contas autorizadas participem da configuração da tabela global.

#### Exemplos de política do IAM para criar tabelas globais
<a name="globaltables_MA_creating_examples"></a>

##### Exemplos de política do IAM para a configuração de duas réplicas
<a name="globaltables_MA_2replica_example"></a>

A configuração de tabelas globais de várias contas segue um fluxo de autorização específico que oferece uma replicação segura. Vamos examinar como isso funciona na prática, analisando um cenário prático em que um cliente deseja estabelecer uma tabela global com duas réplicas. A primeira réplica (ReplicaA) reside na conta A na região ap-east-1, enquanto a segunda réplica (ReplicaB) está na conta B na região eu-south-1.
+ Na conta de origem (conta A), o processo começa com a criação da tabela-réplica primária. O administrador da conta deve anexar uma política baseada em recursos a essa tabela que conceda explicitamente as permissões necessárias à conta de destino (conta B) para realizar a associação. Essa política também autoriza o serviço de replicação do DynamoDB a realizar ações essenciais de replicação.
+ A conta de destino (conta B) segue um processo semelhante, anexando uma política baseada em recursos correspondente ao criar a réplica e mencionando o ARN da tabela de origem a ser usado para criar a réplica. Essa política reflete as permissões concedidas pela conta A, criando uma relação bidirecional confiável. Antes de estabelecer a replicação, o DynamoDB valida essas permissões entre contas para verificar se a autorização adequada está em vigor.

Para estabelecer essa configuração:
+ O administrador da conta A deve primeiro anexar a política baseada em recursos à ReplicaA. Essa política concede explicitamente as permissões necessárias à conta B e ao serviço de replicação do DynamoDB.
+ Da mesma forma, o administrador da conta B deve anexar uma política correspondente à ReplicaB na chamada de criação da tabela, revertendo as referências da conta para conceder as permissões correspondentes à conta A e criar a ReplicaB fazendo referência à ReplicaA como tabela de origem.

------
#### [ 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"
                    ]
                }
            }
        }
    ]
}
```

------

##### Exemplos de política do IAM para a configuração de três réplicas
<a name="globaltables_MA_3replica_example"></a>

Nesta configuração, temos três réplicas ReplicaA, ReplicaB e ReplicaC na conta A, conta B e conta C, respectivamente. A ReplicaA é a primeira e começa como uma tabela regional; em seguida, a ReplicaB e a ReplicaC são adicionadas a ela.
+ O administrador da conta A deve primeiro anexar a política baseada em recursos à ReplicaA, permitindo a replicação com todos os membros e que a entidade principal do IAM tanto da conta B quanto da conta C adicione réplicas.

------
#### [ 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" ] }
        }
    ]
}
```

------
+ O administrador da conta B deve adicionar uma réplica (ReplicaB) apontando para a ReplicaA como origem. A ReplicaB tem a seguinte política, que permite a replicação entre todos os membros e que a conta C adicione uma réplica:

------
#### [ 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" ] }
        }
    ]
}
```

------
+ Por fim, o administrador da conta C cria uma réplica com a política a seguir, que concede permissões de replicação entre todos os membros. A política não permite que nenhuma outra réplica seja adicionada.

------
#### [ 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"
                    ]
                }
            }
        }
    ]
}
```

------

### Atualizar uma tabela global de várias contas
<a name="globaltables_MA_updating"></a>

Para modificar as configurações de réplica de uma tabela global existente usando a API UpdateTable, é preciso ter a seguinte permissão no recurso de tabela na região em que você está fazendo a chamada de API: `dynamodb:UpdateTable`.

Além disso, você pode atualizar outras configurações da tabela global, como políticas de ajuste de escala automático e configurações de tempo de vida. As seguintes permissões são necessárias para essas operações adicionais de atualização:

Para atualizar as configurações de vida útil com a API `UpdateTimeToLive`, é necessário ter a seguinte permissão no recurso de tabela em todas as regiões que contêm réplicas: `dynamodb:UpdateTimeToLive`.

Para atualizar uma política de ajuste de escala automático da réplica com a API `UpdateTableReplicaAutoScaling`, é necessário ter as seguintes permissões no recurso de tabela em todas as regiões que contêm réplicas:
+ `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`

**nota**  
É preciso fornecer permissões `dynamodb:ReplicateSettings` em todas as regiões e contas de réplica para que a tabela de atualização tenha êxito. Se alguma réplica não fornecer permissões para replicar configurações em qualquer réplica na tabela global de várias contas, todas as operações de atualização em todas as réplicas falharão, exibindo `AccessDeniedException`, enquanto as permissões não forem corrigidas.

### Excluir tabelas globais e remover réplicas
<a name="globaltables_MA_deleting"></a>

Para excluir uma tabela global, você deve remover todas as réplicas. Ao contrário da tabela global da mesma conta, não é possível usar `UpdateTable` para excluir uma tabela-réplica em uma região remota e cada réplica deve ser excluída por meio da API `DeleteTable` da conta que a controla.

#### Permissões para excluir tabelas globais e remover réplicas
<a name="globaltables_MA_deleting_permissions"></a>

As permissões a seguir são necessárias tanto para remover réplicas individuais quanto para excluir completamente as tabelas globais. A exclusão de uma configuração de tabela global só remove o relacionamento de replicação entre tabelas em diferentes regiões. Ela não exclui a tabela subjacente do DynamoDB na última região restante. A tabela na última região continua existindo como uma tabela padrão do DynamoDB com os mesmos dados e configurações.

Você precisa das seguintes permissões no recurso de tabela em cada região em que você está removendo uma réplica:
+ `dynamodb:DeleteTable`
+ `dynamodb:DeleteTableReplica`

## Como as tabelas globais usam AWS KMS
<a name="globaltables_MA_kms"></a>

Como todas as tabelas do DynamoDB, as réplicas de tabela global sempre criptografam dados em repouso usando chaves de criptografia armazenadas no AWS Key Management Service (AWS KMS).

**nota**  
Ao contrário da tabela global da mesma conta, réplicas diferentes em uma tabela global de várias contas podem ser configuradas com diferentes tipos de chave do AWS KMS (chave de propriedade da AWS ou chave gerenciada pelo cliente). Não é possível usar chaves gerenciadas pela AWS em tabelas globais de várias contas.

As tabelas globais de várias contas que usam CMKs exigem que a política de chave de cada réplica conceda permissões à entidade principal do serviço de replicação (`replication.dynamodb.amazonaws.com`) do DynamoDB para acessar a chave e usá-la na replicação e no gerenciamento de configurações. As seguintes permissões são necessárias:
+ `kms:Decrypt`
+ `kms:ReEncrypt*`
+ `kms:GenerateDataKey*`
+ `kms:DescribeKey`

**Importante**

O DynamoDB exige acesso à chave de criptografia da réplica para excluir uma réplica. Se você quiser desabilitar ou excluir uma chave gerenciada pelo cliente usada para criptografar uma réplica porque está excluindo a réplica, primeiro exclua a réplica, aguarde a remoção da tabela do grupo de replicação chamando describe em uma das outras réplicas e, em seguida, desabilite ou exclua a chave.

Se você desabilitar ou revogar o acesso do DynamoDB a uma chave gerenciada pelo cliente usada para criptografar uma réplica, a replicação de e para a réplica será interrompida e o status da réplica mudará para `INACCESSIBLE_ENCRYPTION_CREDENTIALS`. Se uma réplica permanecer no estado `INACCESSIBLE_ENCRYPTION_CREDENTIALS` por mais de vinte horas, ela será convertida irreversivelmente em uma tabela do DynamoDB de região única.

### Exemplo de política do AWS KMS
<a name="globaltables_MA_kms_example"></a>

A política AWS KMS permite que o DynamoDB acesse ambas as chaves do AWS KMS para replicação entre as réplicas A e B. As chaves do AWS KMS anexadas à réplica do DynamoDB em cada conta precisam ser atualizadas com a seguinte política:

------
#### [ 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"
                ]
            }
        }
      }
   ]
 }
```

------

# Conceitos básicos sobre faturamento do Amazon DynamoDB para tabelas globais
<a name="global-tables-billing"></a>

Este guia descreve como o faturamento do DynamoDB funciona para tabelas globais, identificando os componentes que contribuem com o custo das tabelas globais, incluindo um exemplo prático. 

As [tabelas globais do Amazon DynamoDB](GlobalTables.md) são um banco de dados totalmente gerenciado, multirregional e sem servidor. As tabelas globais oferecem [disponibilidade de 99,999%](https://aws.amazon.com/dynamodb/sla/), entregando maior resiliência das aplicações e melhor continuidade dos negócios. As tabelas globais replicam as tabelas do DynamoDB automaticamente nas regiões da AWS de sua escolha, portanto, é possível ter alta performance e rapidez de leitura e gravação locais. 

## Como funciona
<a name="global-tables-billing-how-it-works"></a>

O modelo de faturamento para tabelas globais é diferente do aplicado a tabelas de região única do DynamoDB. As operações de gravação para tabelas do DynamoDB de região única são cobradas usando as seguintes unidades:
+ Unidades de solicitação de gravação (WRUs) para o modo de capacidade sob demanda, em que uma WRU é cobrada por cada gravação de até 1 KB
+ Unidades de capacidade de gravação (WCUs) para o modo de capacidade provisionada, em que uma WCU fornece uma gravação por segundo para até 1 KB

Quando você cria uma tabela global adicionando uma tabela de réplica a uma tabela de região única existente, essa tabela de região única se torna uma tabela de réplica, o que significa que as unidades usadas para faturar as gravações na tabela também mudam. As operações de gravação em tabelas de réplica são cobradas usando as seguintes unidades: 
+ Unidades de solicitação de gravação replicadas (rWRUs) para o modo de capacidade sob demanda, em que uma rWRU por tabela de réplica é cobrada por cada gravação de até 1 KB
+ Unidades de capacidade de gravação replicadas (rWCUs) para o modo de capacidade provisionada, em que uma WCU por tabela de réplica fornece uma gravação por segundo para até 1 KB

As atualizações dos índices secundários globais (GSIs) são cobradas usando as mesmas unidades das tabelas do DynamoDB de região única, mesmo que a tabela base do GSI seja uma tabela de réplica. As operações de atualização de GSIs são cobradas usando as seguintes unidades:
+ Unidades de solicitação de gravação (WRUs) para o modo de capacidade sob demanda, em que uma WRU é cobrada por cada gravação de até 1 KB
+ Unidades de capacidade de gravação (WCUs) para o modo de capacidade provisionada, em que uma WCU fornece uma gravação por segundo para até 1 KB

As unidades de gravação replicadas (rWCUs e rWRUs) têm o mesmo preço das unidades de gravação de região única (WCUs e WRUs). Além disso, as taxas de transferência de dados entre regiões se aplicam às tabelas globais, pois os dados são replicados entre regiões. As cobranças de gravação replicada (rWCU ou rWRU) são geradas em cada região que contém uma tabela de réplica para a tabela global.

As operações de leitura de tabelas de região única e de tabelas de réplica usam as seguintes unidades:
+ Unidades de solicitação de leitura (RRUs) para o modo de capacidade sob demanda, em que uma RRU é cobrada por cada leitura altamente consistente de até 4 KB
+ Unidades de capacidade de leitura (RCUs) para tabelas provisionadas, em que uma RCU fornece uma leitura altamente consistente por segundo de até 4 KB

## Modos de consistência e cobrança
<a name="global-tables-billing-consistency-modes"></a>

As unidades de gravação replicadas (rWCUs e rWRUs) usadas para cobrar as operações de gravação são idênticas nos modos de consistência forte multirregional (MRSC) e consistência final multirregional (MREC). As tabelas globais que usam o modo de consistência forte multirregional (MRSC) configurado com testemunha não incorrem em custos de unidades de gravação replicadas (rWCUs e rWRUs), custos de armazenamento ou custos de transferência de dados para replicação para a testemunha.

## Exemplo de faturamento para tabelas globais do DynamoDB
<a name="global-tables-billing-example"></a>

Vamos analisar um exemplo de cenário de vários dias para ver como o faturamento de solicitações de gravação de tabela global funciona na prática (observe que este exemplo leva em conta apenas solicitações de gravação e não inclui as cobranças de restauração de tabelas e transferência de dados entre regiões que seriam geradas no exemplo):

**Dia 1: tabela de região única: **você tem uma tabela de região única sob demanda do DynamoDB chamada Tabela\$1A na região us-west-2. Você grava cem itens de 1 KB na Tabela\$1A. Com relação a operações de gravação de região única, você paga uma unidade de solicitação de gravação (WRU) por 1 KB gravado. Suas cobranças do dia 1 são:
+ 100 WRUs na região us-west-2 para gravações em região única

O total de unidades de solicitação cobradas no dia 1: **100 WRUs**.

**Dia 2: criar uma tabela global:** você cria uma tabela global adicionando uma réplica à Tabela\$1A na região us-east-2. Agora, a Tabela\$1A é uma tabela global com duas tabelas de réplica; uma na região us-west-2 e uma na região us-east-2. Você grava 150 itens de 1 KB na tabela de réplica na região us-west-2. Suas cobranças do dia 2 são:
+ 150 rWRUs na região us-west-2 para gravações replicadas
+ 150 rWRUs na região us-east-2 para gravações replicadas

O total de unidades de solicitação cobradas no dia 2: **300 rWRUs**.

**Dia 3: adicionar um índice secundário global: **você adiciona um índice secundário global (GSI) à tabela de réplica na região us-east-2 que projeta todos os atributos da tabela base (réplica). A tabela global cria automaticamente o GSI na tabela de réplica na região us-west-2. Você grava 200 novos registros de 1 KB na tabela de réplica na região us-west-2. Suas cobranças do dia 3 são:
+ • 200 rWRUs na região us-west-2 para gravações replicadas
+ • 200 WRUs na região us-west-2 para atualizações de GSI
+ • 200 rWRUs na região us-east-2 para gravações replicadas
+ • 200 WRUs na região us-east-2 para atualizações de GSI

Total de unidades de solicitação de gravação cobradas no dia 3: **400 WRUs e 400 rWRUs**.

O total de cobranças de unidade de gravação nos três dias equivale a 500 WRUs (100 WRUs no dia 1 \$1 400 WRUs no dia 3) e 700 rWRUs (300 rWRUs no dia 2 \$1 400 rWRUs no dia 3).

Em resumo, as operações de gravação da tabela de réplica são faturadas em unidades de gravação replicadas em todas as regiões que contêm uma tabela de réplica. Se você tiver índices secundários globais, serão cobradas unidades de gravação pelas atualizações dos GSIs em todas as regiões que contêm um GSI (que em uma tabela global são todas as regiões que contêm uma tabela de réplica). 

# Versões de tabelas globais do DynamoDB
<a name="V2globaltables_versions"></a>

Há duas versões disponíveis das tabelas globais do DynamoDB: tabelas globais versão 2019.11.21 (atual) e tabelas globais versão 2017.11.29 (legada). Recomendamos usar a versão 2019.11.21 (atual) das tabelas globais, pois ela é mais fácil de usar, com suporte em mais regiões e oferece menor custo para a maioria das workloads em comparação com a versão 2017.11.29 (legada).

## Determinar a versão de uma tabela global
<a name="globaltables.DetermineVersion"></a>

### Determinar a versão usando a AWS CLI
<a name="globaltables.CLI"></a>

#### Identificar uma réplica de tabela global da versão 2019.11.21 (atual)
<a name="globaltables.CLI.current"></a>

Para determinar se uma tabela é uma réplica da versão 2019.11.21 (atual) das tabelas globais, invoque o comando `describe-table` para a tabela. Se a saída contiver o atributo `GlobalTableVersion` com o valor "2019.11.21", a tabela é uma réplica da tabela global da versão 2019.11.21 (atual).

Um exemplo de comando CLI para `describe-table`:

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

A saída (abreviada) contém o atributo `GlobalTableVersion` com o valor "2019.11.21", então essa tabela é uma réplica da tabela global da versão 2019.11.21 (atual).

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

#### Identificar uma réplica de tabela global da versão 2017.11.29 (legada)
<a name="globaltables.CLI.legacy"></a>

As tabelas globais versão 2017.11.29 (legada) usam um conjunto dedicado de comandos para gerenciamento global de tabelas. Para determinar se uma tabela é uma réplica da versão 2017.11.21 (legada) das tabelas globais, invoque o comando `describe-global-table` para a tabela. Se você receber uma resposta bem-sucedida, a tabela será uma réplica de tabela global da versão 2017.11.29 (legada). Se o comando `describe-global-table` retornar um erro `GlobalTableNotFoundException`, a tabela não será uma réplica da versão 2017.11.29 (legada).

Um exemplo de comando CLI para `describe-global-table`:

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

O comando retorna uma resposta bem-sucedida, então essa tabela será uma réplica de tabela global da versão 2017.11.29 (legada).

```
{
    "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"
    }
}
```

### Determinar a versão usando o DynamoDB Console
<a name="globaltables.console"></a>

Para identificar a versão de uma réplica de tabela global, faça o seguinte:

1. Abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/home).

1. No painel de navegação, no lado esquerdo do console, selecione **Tables** (Tabelas).

1. Selecione a tabela para a qual você deseja identificar a versão das tabelas globais.

1. Selecione a guia **Global Tables (Tabelas globais)**.

   A seção *Resumo* exibe a versão das tabelas globais em uso.

## Diferenças de comportamento entre as versões herdada e atual
<a name="DiffLegacyVsCurrent"></a>

A lista a seguir descreve as diferenças de comportamento entre as versões herdada e atual das tabelas globais.
+ A versão 2019.11.21 (atual) consome menor capacidade de gravação para várias operações do DynamoDB em comparação à versão 2017.11.29 (herdada) e, portanto, é mais econômica para a maioria dos clientes. As diferenças dessas operações do DynamoDB são as seguintes:
  + Invocar [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html) para um item de 1 KB em uma região e replicar para outras regiões requer 2 rWRUs por região para a 2017.11.29 (herdada), mas apenas 1 rWRU para a 2019.11.21 (atual).
  + Invocar [UpdateItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html) para um item de 1 KB requer 2 rWRUs na região de origem e 1 rWRU por região de destino para a 2017.11.29 (herdada), mas apenas 1 rWRU para as regiões de origem e de destino para a 2019.11.21 (atual).
  + Invocar [DeleteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DeleteItem.html) para um item de 1 KB requer 1 rWRU na região de origem e 2 rWRUs por região de destino para a 2017.11.29 (herdada), mas apenas 1 rWRU para as regiões de origem e de destino para a 2019.11.21 (atual).

  A tabela a seguir mostra o consumo de rWRU das tabelas das versões 2017.11.29 (herdada) e 2019.11.21 (atual) de um item de 1 KB em duas regiões.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/V2globaltables_versions.html)
+ A versão 2017.11.29 (herdada) está disponível somente em 11 Regiões da AWS. No entanto, a versão 2019.11.21 (atual) está disponível em todas as Regiões da AWS.
+ Você deve criar tabelas globais da versão 2017.11.29 (herdada) criando primeiro um conjunto de tabelas regionais vazias e, depois, invocando a API [CreateGlobalTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_CreateGlobalTable.html) para formar a tabela global. As tabelas globais da versão 2019.11.21 (atual) são criadas invocando a API [UpdateTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html) para adicionar uma réplica a uma tabela regional existente.
+ A versão 2017.11.29 (herdada) exige que você esvazie todas as réplicas na tabela antes de adicionar uma réplica em uma nova região (inclusive durante a criação). A versão 2019.11.21 (atual) aceita adicionar réplicas a regiões e removê-las em uma tabela que já contenha dados.
+ A versão 2017.11.29 (herdada) usa o seguinte conjunto dedicado de APIs de ambiente de gerenciamento para gerenciar réplicas:
  + [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)

  A versão 2019.11.21 (atual) usa as APIs [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html) e [UpdateTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html) para gerenciar réplicas.
+ A versão 2017.11.29 (herdada) publica dois registros do DynamoDB Streams para cada gravação. A versão 2019.11.21 (atual) publica apenas um registro do DynamoDB Streams para cada gravação.
+ A versão 2017.11.29 (herdada) preenche e atualiza os atributos `aws:rep:deleting`,`aws:rep:updateregion` e `aws:rep:updatetime`. A versão 2019.11.21 (atual) não preenche nem atualiza esses atributos.
+ A versão 2017.11.29 (herdada) não sincroniza as configurações [Usar a vida útil (TTL) no DynamoDB](TTL.md) entre réplicas. A versão 2019.11.21 (atual) sincroniza as configurações de TTL entre réplicas.
+ A versão 2017.11.29 (herdada) não replica exclusões de TTL para outras réplicas. A versão 2019.11.21 (atual) replica exclusões de TTL para todas as réplicas.
+ A versão 2017.11.29 (herdada) não sincroniza configurações de [ajuste de escala automático](AutoScaling.md) entre réplicas. A versão 2019.11.21 (atual) sincroniza as configurações de ajuste de escala automático entre réplicas.
+ A versão 2017.11.29 (herdada) não sincroniza as configurações de [índice secundário global (GSI)](GSI.md) entre réplicas. A versão 2019.11.21 (atual) sincroniza as configurações do GSI entre réplicas.
+ A versão 2017.11.29 (herdada) não sincroniza as configurações de [criptografia em repouso](encryption.usagenotes.md) entre réplicas. A versão 2019.11.21 (atual) sincroniza as configurações de criptografia em repouso entre réplicas.
+ A versão 2017.11.29 (herdada) publica a métrica `PendingReplicationCount`. A versão 2019.11.21 (atual) não publica essa métrica.

## Atualizar para a versão atual
<a name="upgrading-to-current-version"></a>

### Permissões obrigatórias para a atualização de tabelas globais
<a name="V2globaltables_versions.Notes-permissions"></a>

Para realizar a atualização para a versão 2019.11.21 (atual), é necessário ter permissões `dynamodb:UpdateGlobalTableversion` em todas as regiões com réplicas. Essas permissões se somam às permissões necessárias para acessar o console do DynamoDB e visualizar tabelas.

A política do IAM a seguir concede permissões para atualizar qualquer tabela global para a versão 2019.11.21 (atual).

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

A política do IAM a seguir concede permissões para atualizar apenas a tabela global `Music`, com réplicas em duas regiões, para a versão 2019.11.21 (atual).

```
{
    "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"
            ]
        }
    ]
}
```

### O que esperar durante a atualização
<a name="V2GlobalTablesUpgradeExpectations"></a>
+ Todas as réplicas de tabelas globais continuarão processando o tráfego de leitura e gravação durante a atualização.
+ O processo de atualização requer de alguns minutos a várias horas, dependendo do tamanho da tabela e do número de réplicas.
+ Durante o processo de atualização, o valor de [TableStatus](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TableDescription.html#DDB-Type-TableDescription-TableStatus) mudará de `ACTIVE` para `UPDATING`. É possível ver o status da tabela invocando a API [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html) ou com a visualização **Tabelas** no console do DynamoDB.
+ O ajuste de escala automático não alterará as configurações de capacidade provisionada para uma tabela global enquanto a tabela estiver sendo atualizada. É altamente recomendável definir a tabela como o modo de capacidade [sob demanda](capacity-mode.md#capacity-mode-on-demand) durante a atualização.
+ Se você optar por usar o modo de capacidade [provisionada](provisioned-capacity-mode.md) com ajuste de escala automático durante a atualização, será necessário aumentar o throughput mínimo de leitura e gravação em suas políticas para atender aos aumentos esperados no tráfego e evitar o controle de utilização durante a atualização.
+ A métrica `ReplicationLatency` pode relatar temporariamente picos de latência ou parar de relatar dados de métricas durante o processo de atualização. Consulte mais informações em [ReplicationLatency](metrics-dimensions.md#ReplicationLatency). 
+ Quando o processo de atualização estiver concluído, o status da tabela mudará para `ACTIVE`.

### Comportamento do DynamoDB Streams antes, durante e depois da atualização
<a name="V2GlobalTablesUpgradeDDBStreamsBehavior"></a>

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

### Atualizar para a versão 2019.11.21 (atual)
<a name="V2globaltables_versions.upgrade"></a>

Siga estas etapas para atualizar a versão das tabelas globais do DynamoDB usando o Console de gerenciamento da AWS.

**Como atualizar tabelas globais para a versão 2019.11.21 (atual)**

1. Abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/home). 

1. No painel de navegação no lado esquerdo do console, escolha **Tabelas** e, depois, selecione a tabela global que você deseja atualizar para a versão 2019.11.21 (atual). 

1. Selecione a guia **Global Tables (Tabelas globais)**.

1. Escolha **Update version (Atualizar versão)**.  
![\[Captura de tela do console mostrando o botão Update version (Atualizar versão).\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/GlobalTables-upgrade.png)

1. Leia e concorde com os novos requisitos e escolha **Update version (Atualizar versão)**.

1. Após a conclusão do processo de atualização, a versão de tabelas globais exibida no console muda para **2019.11.21**.

# Melhores práticas para tabelas globais
<a name="globaltables-bestpractices"></a>

As seções a seguir descrevem as melhores práticas para implantar e usar tabelas globais.

## Versão
<a name="globaltables-bestpractices-version"></a>

Há duas versões disponíveis das tabelas globais do DynamoDB: versão 2019.11.21 (atual) e [versão 2017.11.29 (legada)](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/globaltables.V1.html). Você deve usar a versão 2019.11.21 (atual) sempre que possível. 

## Proteção contra exclusão
<a name="globaltables-bestpractices-deletionprotection"></a>

Você deve ativar a proteção contra exclusão nas réplicas de tabelas globais que deseja proteger contra exclusão acidental. Você deve ativar a proteção contra exclusão em cada réplica.

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

O CloudFormation atualmente não oferece suporte à coordenação de recursos multirregionais, como tabelas globais entre pilhas. Se você definir cada réplica de uma tabela global em uma pilha regional separada, encontrará erros devido ao desvio detectado entre as pilhas ao realizar atualizações de réplicas. Para evitar esse problema, você deve escolher uma região como a região de referência para implantar suas tabelas globais e definir todas as réplicas da tabela global na pilha dessa região.

**Importante**  
Você não pode alterar o tipo de um recurso no seu modelo para converter um recurso `AWS::DynamoDB::Table` em um recurso `AWS::DynamoDB::GlobalTable`. Tentar converter uma tabela de região única em uma tabela global alterando o tipo de recurso do CloudFormation pode resultar na exclusão da tabela do DynamoDB.

Em vez disso, você pode utilizar o recurso `AWS::DynamoDB::GlobalTable` para criar uma tabela em uma única região. Essa tabela será implantada como qualquer outra tabela de região única. Se você atualizar a pilha posteriormente para adicionar outras regiões a um recurso, as réplicas serão adicionadas à tabela e ela será convertida com segurança em uma tabela global.

Se você tiver um recurso `AWS::DynamoDB::Table` existente que deseja converter em um recurso `AWS::DynamoDB::GlobalTable`, as etapas recomendadas para converter o tipo de recurso são:

1. Defina a política de exclusão `AWS::DynamoDB::Table` a ser mantida.

1. Remova a tabela da definição de pilha.

1. Adicione réplicas à tabela de região única no console da AWS, convertendo-a em uma tabela global.

1. Importe a tabela global como um novo recurso `AWS::DynamoDB::GlobalTable` para a pilha.

## Backups e recuperação pontual
<a name="globaltables-bestpractices-backups"></a>

Habilitar backups automatizados e recuperação para um ponto no tempo (PITR) para uma réplica em uma tabela global pode ser suficiente para atingir seus objetivos de recuperação de desastres. Os backups de réplicas criados com backup para AWS podem ser replicados automaticamente em todas as regiões para maior resiliência. Considere as metas do seu plano de recuperação de desastres no contexto da alta disponibilidade multirregional ao escolher sua estratégia de backup e habilitação de PITR.

## Projetando para alta disponibilidade multirregional
<a name="globaltables-bestpractices-multiregion"></a>

Para obter orientação prescritiva sobre a implantação de tabelas globais, consulte [Melhores práticas para o design de tabelas globais do DynamoDB](bp-global-table-design.md).

# Trabalhar com itens e atributos no DynamoDB
<a name="WorkingWithItems"></a>

No Amazon DynamoDB, um *item* é uma coleção de atributos. Cada atributo tem um nome e um valor. Um valor de atributo pode ser uma escalar, um conjunto ou um tipo de documento. Para obter mais informações, consulte [Amazon DynamoDB: como funciona](HowItWorks.md).

O DynamoDB fornece quatro operações para a funcionalidade básica criar, ler, atualizar e excluir (CRUD). Todas essas operações são atômicas.
+ `PutItem`: criar um item.
+ `GetItem`: ler um item.
+ `UpdateItem`: atualizar um item.
+ `DeleteItem`: excluir um item.

Cada uma dessas operações exige que você especifique a chave primária do item com o qual deseja trabalhar. Por exemplo, para ler um item usando `GetItem`, você deve especificar a chave de partição e a chave de classificação (se aplicável) desse item.

Além das quatro operações CRUD básicas, o DynamoDB também fornece o seguinte:
+ `BatchGetItem`: ler até 100 itens de uma ou mais tabelas.
+ `BatchWriteItem`: criar ou excluir até 25 itens em uma ou mais tabelas.

Essas operações em lote combinam várias operações CRUD em uma única solicitação. Além disso, as operações em lote leem e gravam itens em paralelo para reduzir as latências de resposta.

Esta seção descreve como usar essas operações e inclui tópicos relacionados, como contadores atômicos e atualizações condicionais. Esta seção também inclui código de exemplo que usa os AWS SDKs. 

**Topics**
+ [Tamanhos e formatos de item do DynamoDB](CapacityUnitCalculations.md)
+ [Ler um item](#WorkingWithItems.ReadingData)
+ [Gravar um item](#WorkingWithItems.WritingData)
+ [Retornar valores](#WorkingWithItems.ReturnValues)
+ [Operações em lote](#WorkingWithItems.BatchOperations)
+ [Contadores atômicos](#WorkingWithItems.AtomicCounters)
+ [Gravações condicionais](#WorkingWithItems.ConditionalUpdate)
+ [Usar expressões no DynamoDB](Expressions.md)
+ [Usar a vida útil (TTL) no DynamoDB](TTL.md)
+ [Consultar tabelas no DynamoDB](Query.md)
+ [Verificar tabelas no DynamoDB](Scan.md)
+ [PartiQL: uma linguagem de consultas compatível com SQL para o Amazon DynamoDB](ql-reference.md)
+ [Trabalhar com itens: Java](JavaDocumentAPIItemCRUD.md)
+ [Trabalhar com itens: .NET](LowLevelDotNetItemCRUD.md)

# Tamanhos e formatos de item do DynamoDB
<a name="CapacityUnitCalculations"></a>

As tabelas do DynamoDB são sem esquema, exceto para a chave primária. Portanto, os itens em uma tabela podem ter atributos, tamanhos e tipos de dados diferentes.

O tamanho total de um item é a soma dos tamanhos de seus nomes e valores de atributos, somado a qualquer sobrecarga aplicável como descrito abaixo. Você pode usar as seguintes diretrizes para estimar os tamanhos de atributo:
+ Strings são Unicode com codificação binária UTF-8. O tamanho de uma string é *(número de bytes codificados por UTF-8 do nome do atributo) \$1 (número de bytes codificados em UTF-8)*.
+ Os números são de tamanho variável, com até 38 dígitos significativos. Zeros iniciais e finais são cortados. O tamanho de um número é aproximadamente *(número de bytes codificados por UTF-8 do nome do atributo) \$1 (1 byte por dois dígitos significativos) \$1 (1 byte)*.
+ Um valor binário deve ser codificado no formato base64 antes que possa ser enviado para o DynamoDB, mas o tamanho de byte bruto do valor é usado para calcular o tamanho. O tamanho de um atributo binário é *(número de bytes codificados por UTF-8 do nome do atributo) \$1 (número de bytes brutos).*
+ O tamanho de um atributo nulo ou de um atributo booliano é *(número de bytes codificados por UTF-8 do nome do atributo) \$1 (1 byte)*.
+ Um atributo do tipo `List` ou `Map` requer 3 bytes de sobrecarga, independentemente de seu conteúdo. O tamanho de uma `List` ou um `Map` é *(número de bytes codificados por UTF-8 do nome do atributo) \$1 soma (tamanho dos elementos aninhados) \$1 (3 bytes)*. O tamanho de uma `List` ou um `Map` vazio é *(número de bytes codificados por UTF-8 do nome do atributo) \$1 (3 bytes)*.
+ Cada elemento da `List` ou do `Map` também requer 1 byte de sobrecarga.

**nota**  
Recomendamos que você escolha nomes mais curtos para os atributos. Isso ajuda a reduzir a quantidade de armazenamento necessária, mas também pode reduzir a quantidade de RCU/WCUs usada.

Para fins de faturamento de armazenamento, cada item inclui uma sobrecarga de armazenamento por item que depende dos recursos ativados.
+ Todos os itens no DynamoDB requerem 100 bytes de sobrecarga de armazenamento para indexação.
+ Alguns recursos do DynamoDB (tabelas globais, transações, captura de dados de alteração para o Kinesis Data Streams com o DynamoDB) exigem sobrecarga de armazenamento adicional para contabilizar atributos criados pelo sistema resultantes da ativação desses recursos. Por exemplo, tabelas globais exigem 48 bytes adicionais de sobrecarga de armazenamento.

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

Para ler um item de uma tabela do DynamoDB use a operação `GetItem`. Você deve fornecer o nome da tabela, juntamente com a chave primária do item desejado.

**Example**  
O exemplo da AWS CLI a seguir mostra como ler um item da tabela `ProductCatalog`.  

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

**nota**  
Com `GetItem`, você deve especificar a chave primária *inteira*, não apenas parte dela. Por exemplo, se uma tabela tiver uma chave primária composta (chave de partição e chave de classificação), você deverá fornecer um valor para a chave de partição e um valor para a chave de classificação.

A solicitação `GetItem` executa uma leitura final consistente, por padrão. Você pode usar o parâmetro `ConsistentRead` para solicitar uma leitura altamente consistente. (Isso consome unidades de capacidade de leitura adicionais, mas retorna a versão mais recente do item.)

`GetItem` retornará todos os atributos do item. Você pode usar uma *expressão de projeção* para retornar apenas alguns dos atributos. Para obter mais informações, consulte [Usar expressões de projeção no DynamoDB](Expressions.ProjectionExpressions.md).

Para retornar o número de unidades de capacidade de leitura consumidas por `GetItem`, defina o parâmetro `ReturnConsumedCapacity` como `TOTAL`.

**Example**  
O exemplo da AWS Command Line Interface (AWS CLI) a seguir mostra alguns dos parâmetros opcionais de `GetItem`.  

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

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

Para criar, atualizar ou excluir um item em uma tabela do DynamoDB use uma das seguintes operações:
+ `PutItem`
+ `UpdateItem`
+ `DeleteItem`

Para cada uma dessas operações, você deve especificar a chave primária inteira, não apenas parte dela. Por exemplo, se uma tabela tiver uma chave primária composta (chave de partição e chave de classificação), você deve fornecer um valor para a chave de partição e um valor para a chave de classificação.

Para retornar o número de unidades de capacidade de gravação consumidas por qualquer uma dessas operações, defina o parâmetro `ReturnConsumedCapacity` de uma das seguintes formas: 
+ `TOTAL`: retorna o número total de unidades de capacidade de gravação consumidas.
+ `INDEXES`: retorna o número total de unidades de capacidade de gravação consumidas, com subtotais para a tabela e para todos os índices secundários que foram afetados pela operação.
+ `NONE`: nenhum detalhe da capacidade de gravação é retornado. (Esse é o padrão.)

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

`PutItem` cria um novo item. Se um item com a mesma chave já existir na tabela, ele será substituído pelo novo item.

**Example**  
Gravar um novo item na tabela `Thread`. A chave primária de `Thread` consiste em `ForumName` (chave de partição) e `Subject` (chave de classificação).  

```
aws dynamodb put-item \
    --table-name Thread \
    --item file://item.json
```
Os argumentos de `--item` são armazenados no arquivo `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>

Se um item com a chave especificada não existir, `UpdateItem` criará um item. Caso contrário, ele modificará os atributos de um item existente.

Você usa uma *expressão de atualização* para especificar os atributos que deseja modificar e seus novos valores. Para obter mais informações, consulte [Usar expressões de atualização no DynamoDB](Expressions.UpdateExpressions.md). 

Na expressão de atualização, use valores de atributos de expressão como espaços reservados para os valores reais. Para obter mais informações, consulte [Usar valores de atributos de expressão no DynamoDB](Expressions.ExpressionAttributeValues.md).

**Example**  
Modifique vários atributos no item `Thread`. O parâmetro opcional `ReturnValues` mostra o item como ele aparece após a atualização. Para obter mais informações, consulte [Retornar valores](#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
```

Os argumentos de `--key` são armazenados no arquivo `key.json`.

```
{
    "ForumName": {"S": "Amazon DynamoDB"},
    "Subject": {"S": "New discussion thread"}
}
```

Os argumentos de `--expression-attribute-values` são armazenados no arquivo `expression-attribute-values.json`.

```
{
    ":zero": {"N":"0"},
    ":lastpostedby": {"S":"barney@example.com"}
}
```

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

`DeleteItem` exclui o item com a chave especificada.

**Example**  
O exemplo da AWS CLI a seguir mostra como excluir o item `Thread`.  

```
aws dynamodb delete-item \
    --table-name Thread \
    --key file://key.json
```

## Retornar valores
<a name="WorkingWithItems.ReturnValues"></a>

Em alguns casos, talvez você queira que o DynamoDB retorne determinados valores de atributos como eles apareciam antes ou depois de modificados. As operações `PutItem`, `UpdateItem` e `DeleteItem` têm um parâmetro `ReturnValues` que você pode usar para retornar os valores de atributo antes ou depois que eles sejam modificados.

O valor padrão de `ReturnValues` é `NONE`, o que significa que o DynamoDB não retornará nenhuma informação sobre os atributos que foram modificados. 

Veja a seguir as outras configurações válidas de `ReturnValues`, organizadas pela operação da API do DynamoDB.

### PutItem
<a name="WorkingWithItems.ReturnValues.PutItem"></a>
+ `ReturnValues`: `ALL_OLD`
  + Se você substituir um item existente, `ALL_OLD` retornará o item inteiro, conforme ele aparecia antes da substituição.
  + Se você gravar um item que não existe, `ALL_OLD` não terá efeito.

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

O uso mais comum de `UpdateItem` é para atualizar um item existente. No entanto, `UpdateItem` realmente executa um *upsert*, o que significa que ele criará o item automaticamente se ele ainda não existir.
+ `ReturnValues`: `ALL_OLD`
  + Se você atualizar um item existente, `ALL_OLD` retornará o item inteiro, conforme ele aparecia antes da atualização.
  + Se você atualizar um item que não existe (upsert), `ALL_OLD` não terá efeito.
+ `ReturnValues`: `ALL_NEW`
  + Se você atualizar um item existente, `ALL_NEW` retornará o item inteiro, conforme ele aparecia depois da atualização.
  + Se você atualizar um item que não existe (upsert), `ALL_NEW` retornará o item inteiro.
+ `ReturnValues`: `UPDATED_OLD`
  + Se você atualizar um item existente, `UPDATED_OLD` retornará apenas os atributos atualizados, como eles apareciam antes da atualização.
  + Se você atualizar um item que não existe (upsert), `UPDATED_OLD` não terá efeito.
+ `ReturnValues`: `UPDATED_NEW`
  + Se você atualizar um item existente, `UPDATED_NEW` retornará apenas os atributos afetados, como eles apareciam depois da atualização.
  + Se você atualizar um item que não existe (upsert), `UPDATED_NEW` retornará apenas os atributos atualizados, conforme eles aparecem após a atualização.

### DeleteItem
<a name="WorkingWithItems.ReturnValues.DeleteItem"></a>
+ `ReturnValues`: `ALL_OLD`
  + Se você excluir um item existente, `ALL_OLD` retornará o item inteiro, como ele aparecia antes de você excluí-lo.
  + Se você excluir um item que não existe, `ALL_OLD` não retornará nenhum dado.

## Operações em lote
<a name="WorkingWithItems.BatchOperations"></a>

Para aplicações que precisam ler ou gravar vários itens, o DynamoDB fornece as operações `BatchGetItem` e `BatchWriteItem`. Usar essas operações pode reduzir o número de round trips da rede da sua aplicação para o DynamoDB. Além disso, o DynamoDB executa as operações de leitura ou gravação individuais em paralelo. Suas aplicações se beneficiam desse paralelismo sem a necessidade de gerenciar a simultaneidade ou threading.

As operações em lote são essencialmente wrappers em torno de várias solicitações de leitura ou de gravação. Por exemplo, se uma solicitação `BatchGetItem` contiver cinco itens, o DynamoDB executará cinco operações `GetItem` em seu nome. Da mesma forma, se uma solicitação `BatchWriteItem` contiver duas solicitações Put e quatro solicitações Delete, o DynamoDB realizará duas solicitações `PutItem` e quatro `DeleteItem`.

Em geral, não há falha em uma operação em lote, a menos que haja falha em *todas* as solicitações no lote. Por exemplo, suponha que você execute uma operação `BatchGetItem`, mas que haja falha em uma das solicitações `GetItem` individuais no lote. Nesse caso, `BatchGetItem` retorna as chaves e os dados da solicitação `GetItem` com falha. As outras solicitações `GetItem` no lote não são afetadas.

### BatchGetItem
<a name="WorkingWithItems.BatchOperations.BatchGetItem"></a>

Uma única operação `BatchGetItem` pode conter até 100 solicitações `GetItem` individuais e recuperar até 16 MB de dados. Além disso, uma operação `BatchGetItem` pode recuperar itens de várias tabelas.

**Example**  
Recuperar dois itens da tabela `Thread` usando uma expressão de projeção para retornar apenas alguns dos atributos.  

```
aws dynamodb batch-get-item \
    --request-items file://request-items.json
```
Os argumentos de `--request-items` são armazenados no arquivo `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>

A operação `BatchWriteItem` pode conter até 25 solicitações `PutItem` e `DeleteItem` individuais e gravar até 16 MB de dados. (O tamanho máximo de um item individual é 400 KB.) Além disso, uma operação `BatchWriteItem` pode inserir ou excluir itens em várias tabelas. 

**nota**  
`BatchWriteItem` não é compatível com solicitações `UpdateItem`.

**Example**  
Gravar dois itens na tabela `ProductCatalog`.  

```
aws dynamodb batch-write-item \
    --request-items file://request-items.json
```
Os argumentos de `--request-items` são armazenados no arquivo `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" }
                }
            }
        }
    ]
}
```

## Contadores atômicos
<a name="WorkingWithItems.AtomicCounters"></a>

Você pode usar a operação `UpdateItem` para implementar um *contador atômico*, um atributo numérico que é incrementado incondicionalmente sem interferir em outras solicitações de gravação. (Todas as solicitações de gravação são aplicadas na ordem em que foram recebidas.) Com um contador atômico, as atualizações não são imutáveis. Em outras palavras, o valor numérico é incrementado ou reduzido cada vez que você chama `UpdateItem`. Se o valor de incremento usado para atualizar o contador atômico for positivo, isso poderá causar contagem a mais. Se o valor do incremento for negativo, isso poderá causar contagem a menos.

Você pode usar um contador atômico para rastrear o número de visitantes de um site. Neste caso, sua aplicação poderia incrementar um valor numérico, independentemente do seu valor atual. Se houve falha em uma operação `UpdateItem`, a aplicação poderá simplesmente tentar a operação novamente. Isso arriscaria atualizar o contador duas vezes, mas provavelmente você poderia tolerar uma pequena contagem a mais ou a menos de visitantes do site.

Um contador atômico não seria apropriado onde uma contagem a mais ou a menos não pudesse ser tolerada (por exemplo, em uma aplicação bancária). Nesse caso, é mais seguro usar uma atualização condicional em vez de um contador atômico.

Para obter mais informações, consulte [Incrementar e reduzir atributos numéricos](Expressions.UpdateExpressions.md#Expressions.UpdateExpressions.SET.IncrementAndDecrement).

**Example**  
O exemplo da AWS CLI a seguir incrementa o `Price` de um produto em 5. Neste exemplo, sabia-se que o item existia antes da atualização do contador. Como `UpdateItem` não é idempotente, o `Price` aumenta cada vez que você executa esse código.   

```
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
```

## Gravações condicionais
<a name="WorkingWithItems.ConditionalUpdate"></a>

Por padrão, as operações de gravação do DynamoDB (`PutItem` e `DeleteItem`) são *incondicionais*: cada operação substitui um item existente que tem a chave primária especificada.

Opcionalmente, o DynamoDB é compatível com gravações condicionais dessas operações. Uma gravação condicional terá êxito somente se os atributos de item atenderem a uma ou mais condições esperadas. Caso contrário, um erro será retornado.

As gravações condicionais comparam suas condições com a versão atualizada mais recentemente do item. Observe que, se o item não existisse anteriormente ou se a operação bem-sucedida mais recente referente a esse item tivesse sido uma exclusão, a gravação condicional não encontraria nenhum item anterior.

 Gravações condicionais são úteis em muitas situações. Por exemplo, talvez você queira que uma operação `PutItem` tenha êxito somente se já não houver um item com a mesma chave primária. Ou você poderia impedir que uma operação `UpdateItem` modificasse um item, se um de seus atributos tivesse um determinado valor.

As gravações condicionais são úteis nos casos em que vários usuários tentam modificar o mesmo item. Considere o diagrama a seguir, no qual dois usuários (Alice e Bob) estão trabalhando com o mesmo item de uma tabela do DynamoDB.

![\[Os usuários Alice e Bob tentam modificar um item com Id 1, demonstrando a necessidade de gravações condicionais.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/update-no-condition.png)


Suponha que Alice usa a AWS CLI para atualizar o atributo `Price` para 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
```

Os argumentos de `--expression-attribute-values` são armazenados no arquivo `expression-attribute-values.json`:

```
{
    ":newval":{"N":"8"}
}
```

Agora, suponha que Bob emita uma solicitação `UpdateItem` semelhante mais tarde, mas altere o `Price` para 12. Para Bob, o parâmetro `--expression-attribute-values` tem a seguinte aparência.

```
{
    ":newval":{"N":"12"}
}
```

A solicitação de Bob é bem-sucedida, mas a atualização anterior de Alice é perdida.

Para solicitar uma condicional `PutItem`, `DeleteItem` ou `UpdateItem`, especifique uma expressão de condição. Uma *expressão de condição* é uma string que contém nomes de atributos, operadores condicionais e funções internas. A expressão inteira deve ser avaliada como verdadeira. Caso contrário, haverá falha na operação.

Agora, considere o seguinte diagrama que mostra como gravações condicionais impediriam que a atualização de Alice fosse substituída.

![\[Gravação condicional impedindo que a atualização do usuário Bob sobrescreva a alteração da usuária Alice no mesmo item.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/update-yes-condition.png)


Alice primeiro tenta atualizar `Price` para 8, mas somente se o `Price` atual for 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
```

Os argumentos de `--expression-attribute-values` são armazenados no arquivo `expression-attribute-values.json`.

```
{
    ":newval":{"N":"8"},
    ":currval":{"N":"10"}
}
```

A atualização de Alice é bem-sucedida porque a condição é avaliada como verdadeira.

Em seguida, Bob tenta atualizar o `Price` para 12, mas somente se o `Price` atual for 10. Para Bob, o parâmetro `--expression-attribute-values` tem a seguinte aparência.

```
{
    ":newval":{"N":"12"},
    ":currval":{"N":"10"}
}
```

Como Alice mudou o `Price` para 8 anteriormente, a expressão de condição é avaliada como falsa, e há falha na atualização de Bob.

Para obter mais informações, consulte [Exemplo de expressão de condição do DynamoDB na CLI](Expressions.ConditionExpressions.md).

### Idempotência de gravação condicional
<a name="WorkingWithItems.ConditionalWrites.Idempotence"></a>

As gravações condicionais podem ser *imutáveis* se a verificação condicional estiver no mesmo atributo que está sendo atualizado. Isso significa que o DynamoDB realiza uma determinada solicitação de gravação somente se certos valores de atributo no item corresponderem aos valores estimados no momento da solicitação. 

Por exemplo, suponha que você emita uma solicitação de `UpdateItem` para aumentar o `Price` de um item em 3, mas somente se o `Price` atual for 20. Depois de enviar a solicitação, mas antes de obter os resultados de volta, ocorre um erro de rede e você não sabe se a solicitação teve êxito. Como essa gravação condicional é imutável, você pode tentar novamente a mesma solicitação de `UpdateItem`, e o DynamoDB atualizará o item somente se `Price` for igual a 20 no momento.

### Unidades de capacidade consumidas por gravações condicionais
<a name="WorkingWithItems.ConditionalWrites.ReturnConsumedCapacity"></a>

Se uma `ConditionExpression` for avaliada como false durante uma gravação condicional, o DynamoDB ainda consumirá capacidade de gravação da tabela. A quantidade consumida depende do tamanho do item existente (ou no mínimo 1). Por exemplo, se um item existente tiver 300 kb e o item que você está tentando criar ou atualizar tiver 310 kb, as unidades de capacidade de gravação consumidas serão 300 se a condição falhar e 310 se a condição for bem-sucedida. Se for um item novo (nenhum item existente), as unidades de capacidade de gravação consumidas serão 1 se a condição falhar e 310 se a condição for bem-sucedida.

**nota**  
As operações de gravação consomem apenas unidades de capacidade de *gravação*. Elas nunca consomem unidades de capacidade de *leitura*.

Uma gravação condicional com falha retorna uma `ConditionalCheckFailedException`. Quando isso ocorre, você não recebe nenhuma informação na resposta sobre a capacidade de gravação que foi consumida.

Para retornar o número de unidades de capacidade de gravação consumidas durante uma gravação condicional, você deve usar o parâmetro `ReturnConsumedCapacity`:
+ `TOTAL`: retorna o número total de unidades de capacidade de gravação consumidas.
+ `INDEXES`: retorna o número total de unidades de capacidade de gravação consumidas, com subtotais para a tabela e para todos os índices secundários que foram afetados pela operação.
+ `NONE`: nenhum detalhe da capacidade de gravação é retornado. (Esse é o padrão.)

  

**nota**  
Ao contrário de um índice secundário global, um índice secundário local compartilha a capacidade de throughput provisionada com sua tabela. A atividade de leitura e gravação em um índice secundário local consome a capacidade de throughput provisionado da tabela.

# Usar expressões no DynamoDB
<a name="Expressions"></a>

No Amazon DynamoDB, você pode usar *expressões* para especificar quais atributos devem ser lidos em um item, gravar dados quando uma condição é atendida, especificar como atualizar um item, definir consultas e filtrar os resultados de uma consulta.

Esta tabela descreve a gramática de expressão básica e os tipos de expressão disponíveis.


| Tipo de expressão | Descrição | 
| --- | --- | 
| Expressão de projeção | Uma expressão de projeção identifica os atributos que você deseja recuperar de um item ao usar operações como GetItem, Query ou Scan. | 
| Expressão de condição | Uma expressão de condição determina quais itens devem ser modificados ao usar as operações PutItem, UpdateItem e DeleteItem. | 
| Expressão de atualização | Uma expressão de atualização especifica como UpdateItem modificará os atributos de um item. Por exemplo, definindo um valor escalar ou removendo elementos de uma lista ou de um mapa. | 
| Expressão de condição principal | Uma expressão de condição principal determina quais itens uma consulta lerá em uma tabela ou índice. | 
| Expressão de filtro | Uma expressão de filtro determina quais itens dos resultados de Query devem ser retornados para você. Todos os outros resultados serão descartados. | 

Para saber mais sobre sintaxe de expressão e mais detalhes sobre cada tipo de expressão, consulte as seções a seguir.

**Topics**
+ [Referir-se a atributos de item ao usar expressões no DynamoDB](Expressions.Attributes.md)
+ [Nomes (aliases) de atributo de expressão no DynamoDB](Expressions.ExpressionAttributeNames.md)
+ [Usar valores de atributos de expressão no DynamoDB](Expressions.ExpressionAttributeValues.md)
+ [Usar expressões de projeção no DynamoDB](Expressions.ProjectionExpressions.md)
+ [Usar expressões de atualização no DynamoDB](Expressions.UpdateExpressions.md)
+ [Expressões de condição e filtro, operadores e funções no DynamoDB](Expressions.OperatorsAndFunctions.md)
+ [Exemplo de expressão de condição do DynamoDB na CLI](Expressions.ConditionExpressions.md)

**nota**  
Para fins de compatibilidade com versões anteriores, o DynamoDB também aceita parâmetros condicionais que não usam expressões. Para obter mais informações, consulte [Parâmetros condicionais legados do DynamoDB](LegacyConditionalParameters.md).  
Novas aplicações devem usar expressões em vez de parâmetros herdados.

# Referir-se a atributos de item ao usar expressões no DynamoDB
<a name="Expressions.Attributes"></a>

Esta seção descreve como consultar atributos de item em uma expressão no Amazon DynamoDB. Você pode trabalhar com qualquer atributo, mesmo se ele estiver profundamente aninhado dentro de várias listas e mapas.

**Topics**
+ [Atributos de nível superior](#Expressions.Attributes.TopLevelAttributes)
+ [Atributos aninhados](#Expressions.Attributes.NestedAttributes)
+ [Caminhos de documentos](#Expressions.Attributes.NestedElements.DocumentPathExamples)

**Um item de exemplo: ProductCatalog**  
Os exemplos desta página usam o item de amostra a seguir na tabela `ProductCatalog`. (Esta tabela é descrita na seção [Exemplos de tabelas e dados para uso no 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"
 }
```

Observe o seguinte:
+ O valor da chave de partição (`Id`) é `123`. Não há chave de classificação.
+ A maioria dos atributos têm tipos de dados escalares, como `String`, `Number`, `Boolean` e `Null`.
+ Um atributo (`Color`) é um `String Set`.
+ Os atributos a seguir são tipos de dados de documento:
  + Uma lista de `RelatedItems`. Cada elemento é um `Id` de um produto relacionado.
  + Um mapa de `Pictures`. Cada elemento é uma breve descrição de uma imagem, juntamente com um URL para o arquivo de imagem correspondente.
  + Um mapa de `ProductReviews`. Cada elemento representa uma classificação e uma lista de avaliações correspondentes a essa classificação. Inicialmente, esse mapa é preenchido com avaliações de cinco estrelas e de uma estrela.

## Atributos de nível superior
<a name="Expressions.Attributes.TopLevelAttributes"></a>

Um atributo será considerado como de *nível superior* se ele não estiver incorporado a outro atributo. Para o item do `ProductCatalog`, os atributos de nível superior são os seguintes:
+ `Id`
+ `Title`
+ `Description`
+ `BicycleType`
+ `Brand`
+ `Price`
+ `Color`
+ `ProductCategory`
+ `InStock`
+ `QuantityOnHand`
+ `RelatedItems`
+ `Pictures`
+ `ProductReviews`
+ `Comment`
+ `Safety.Warning`

Todos esses atributos de nível superior são escalares, exceto `Color` (lista), `RelatedItems` (lista), `Pictures` (mapa) e `ProductReviews` (mapa).

## Atributos aninhados
<a name="Expressions.Attributes.NestedAttributes"></a>

Um atributo é considerado *aninhado* se ele estiver incorporado a outro atributo. Para acessar um atributo aninhado, utiliza-se *operadores de cancelamento de referência*:
+ `[n]`: para elementos de lista
+ `.` (ponto): para elementos de mapa

### Acesso a elementos de lista
<a name="Expressions.Attributes.NestedElements.AccessingListElements"></a>

O operador de desreferência de um elemento de lista é **[*N*]**, onde *n* é o número do elemento. Os elementos de lista são baseados em zero, portanto, [0] representa o primeiro elemento na lista, [1] representa o segundo, e assim por diante. Veja alguns exemplos:
+ `MyList[0]`
+ `AnotherList[12]`
+ `ThisList[5][11]`

O próprio elemento `ThisList[5]` é uma lista aninhada. Portanto, `ThisList[5][11]` refere-se ao décimo segundo elemento na lista.

O número dentro de colchetes deve ser um inteiro não negativo. Portanto, as seguintes expressões são inválidas:
+ `MyList[-1]`
+ `MyList[0.4]`

### Acessar elementos de mapas
<a name="Expressions.Attributes.NestedElements.AccessingMapElements"></a>

O operador de cancelamento de referência de um elemento de mapa é **.** (um ponto). Use um ponto como um separador entre os elementos em um mapa:
+ `MyMap.nestedField`
+ `MyMap.nestedField.deeplyNestedField`

## Caminhos de documentos
<a name="Expressions.Attributes.NestedElements.DocumentPathExamples"></a>

Em uma expressão, você usa um *caminho de documento* para informar ao DynamoDB onde encontrar um atributo. Para um atributo de nível superior, o caminho do documento é simplesmente o nome do atributo. Para um atributo aninhado, você pode construir o caminho do documento usando operadores de cancelamento de referência.

Veja a seguir alguns exemplos de caminhos de documentos. (Consulte o item mostrado em [Referir-se a atributos de item ao usar expressões no DynamoDB](#Expressions.Attributes).)
+ Um atributo escalar de nível superior.

   `Description`
+ Um atributo de lista de nível superior. (Isso retorna a lista inteira, não apenas alguns dos elementos.)

  `RelatedItems`
+ O terceiro elemento na lista `RelatedItems`. (Lembre-se de que os elementos de lista são baseadas em zero.)

  `RelatedItems[2]`
+ A imagem da visão frontal do produto.

  `Pictures.FrontView`
+ Todas as críticas de cinco estrelas.

  `ProductReviews.FiveStar`
+ A primeira das críticas de cinco estrelas.

  `ProductReviews.FiveStar[0]`

**nota**  
A profundidade máxima de um caminho de documento é 32. Portanto, o número de operadores de cancelamento de referência em um caminho não pode exceder esse limite.

É possível usar qualquer nome de atributo em um caminho de documento, desde ele que cumpra estes requisitos:
+ O primeiro caractere deve ser `a-z` ou `A-Z` e ou `0-9`
+ O segundo caractere (se presente) deve ser `a-z`, `A-Z`

**nota**  
Se um nome de atributo não cumprir essas exigências, você deverá definir um nome de atributo de expressão como um espaço reservado.

Para obter mais informações, consulte [Nomes (aliases) de atributo de expressão no DynamoDB](Expressions.ExpressionAttributeNames.md).

# Nomes (aliases) de atributo de expressão no DynamoDB
<a name="Expressions.ExpressionAttributeNames"></a>

Um *nome de atributo de expressão* é um alias (ou espaço reservado) usado em uma expressão do Amazon DynamoDB como alternativa ao nome de atributo real. Um nome de atributo de expressão deve começar com um sinal de cerquilha (`#`) seguido de um ou mais caracteres alfanuméricos. O sublinhado (`_`) também é permitido.

Esta seção descreve várias situações em que você precisa usar nomes de atributos de expressão.

**nota**  
Os exemplos desta seção usam a AWS Command Line Interface (AWS CLI). 

**Topics**
+ [Palavras reservadas](#Expressions.ExpressionAttributeNames.ReservedWords)
+ [Nomes de atributos com caracteres especiais](#Expressions.ExpressionAttributeNames.AttributeNamesContainingSpecialCharacters)
+ [Atributos aninhados](#Expressions.ExpressionAttributeNames.NestedAttributes)
+ [Consultar nomes de atributo de forma repetida](#Expressions.ExpressionAttributeNames.RepeatingAttributeNames)

## Palavras reservadas
<a name="Expressions.ExpressionAttributeNames.ReservedWords"></a>

Algumas vezes, pode ser necessário escrever uma expressão que contém um nome de atributo que está em conflito com uma palavra reservada do DynamoDB. (Para obter uma lista completa de palavras reservadas, consulte [Palavras reservadas no DynamoDB](ReservedWords.md).)

Por exemplo, haveria falha no seguinte exemplo da AWS CLI porque `COMMENT` é uma palavra reservada.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "Comment"
```

Para resolver esse problema, substitua `Comment` por um nome de atributo de expressão, como `#c`. A `#` (cerquilha) é obrigatória e indica que esse é um espaço reservado para um nome de atributo. O exemplo da AWS CLI agora deve ter a seguinte aparência.

```
aws dynamodb get-item \
     --table-name ProductCatalog \
     --key '{"Id":{"N":"123"}}' \
     --projection-expression "#c" \
     --expression-attribute-names '{"#c":"Comment"}'
```

**nota**  
Se o nome de um atributo começar com um número, contiver um espaço ou incluir uma palavra reservada, você *deverá* usar um nome de atributo de expressão para substituir esse nome de atributo na expressão.

## Nomes de atributos com caracteres especiais
<a name="Expressions.ExpressionAttributeNames.AttributeNamesContainingSpecialCharacters"></a>

Em uma expressão, um ponto (“.”) é interpretado como um caractere de separação em um caminho de documento. No entanto, o DynamoDB também permite que você use um ponto e outros caracteres especiais, como um hífen (“-”) como parte do nome de um atributo. Isso pode ser ambíguo em alguns casos. Para ilustrar, vamos supor que você queira recuperar o atributo `Safety.Warning` de um item do `ProductCatalog` (consulte [Referir-se a atributos de item ao usar expressões no DynamoDB](Expressions.Attributes.md)).

Suponha que você queira acessar `Safety.Warning` usando uma expressão de projeção.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "Safety.Warning"
```

O DynamoDB retorna um resultado vazio, em vez da string esperada (“”). ("`Always wear a helmet`"). Isso ocorre porque o DynamoDB interpreta um ponto em uma expressão como um separador de caminho de documento. Neste caso, defina um nome de atributo de expressão (por exemplo, `#sw`) como um substituto para `Safety.Warning`. Você poderia usar a seguinte expressão de projeção.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "#sw" \
    --expression-attribute-names '{"#sw":"Safety.Warning"}'
```

Em seguida, o DynamoDB deverá retornar o resultado correto.

**nota**  
Se o nome de um atributo contiver um ponto (“.”) ou um hífen (“-”), você *deverá* usar um nome de atributo de expressão para substituir o nome desse atributo na expressão.

## Atributos aninhados
<a name="Expressions.ExpressionAttributeNames.NestedAttributes"></a>

Suponha que você queira acessar o atributo `ProductReviews.OneStar` aninhado. No nome de atributo de expressão, o DynamoDB trata o ponto (“.”) como um caractere no nome de um atributo. Para consultar o atributo aninhado, defina um nome de atributo de expressão para cada elemento no caminho do documento:
+ `#pr — ProductReviews`
+ `#1star — OneStar`

Você poderia usar `#pr.#1star` para a expressão de projeção.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "#pr.#1star"  \
    --expression-attribute-names '{"#pr":"ProductReviews", "#1star":"OneStar"}'
```

Em seguida, o DynamoDB deverá retornar o resultado correto.

## Consultar nomes de atributo de forma repetida
<a name="Expressions.ExpressionAttributeNames.RepeatingAttributeNames"></a>

Os nomes de atributo de expressão são úteis quando você precisa consultar o mesmo nome de atributo repetidamente. Por exemplo, considere a seguinte expressão para recuperar algumas das revisões de um item do `ProductCatalog`.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "ProductReviews.FiveStar, ProductReviews.ThreeStar, ProductReviews.OneStar"
```

Para tornar isso mais conciso, você pode substituir `ProductReviews` por um nome de atributo de expressão, como `#pr`. A expressão revisada agora teria a seguinte aparência.
+  `#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"}'
```

Caso defina um nome de atributo de expressão, você deverá usá-lo de forma consistente na expressão inteira. Além disso, não é possível omitir o símbolo `#`. 

# Usar valores de atributos de expressão no DynamoDB
<a name="Expressions.ExpressionAttributeValues"></a>

Os *valores de atributo de expressão* no Amazon DynamoDB atuam como variáveis. Eles substituem os valores reais que você deseja comparar; isto é, valores que talvez não conheça antes do tempo de execução. Um valor de atributo de expressão deve começar com um sinal de dois pontos (`:`) seguido por um ou mais caracteres alfanuméricos.

Por exemplo, suponha que você quisesse retornar todos os itens de `ProductCatalog` que estão disponíveis em `Black` e custam `500` ou menos. Você poderia usar uma operação `Scan` com uma expressão de filtro, como neste exemplo da 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
```

Os argumentos de `--expression-attribute-values` são armazenados no arquivo `values.json`.

```
{
    ":c": { "S": "Black" },
    ":p": { "N": "500" }
}
```

Caso defina um valor de atributo de expressão, você deverá usá-lo de forma consistente na expressão inteira. Além disso, não é possível omitir o símbolo `:`. 

Os valores de atributo de expressão são usados com expressões de condições de chaves, expressões de condições, expressões de atualização e expressões de filtro.

# Usar expressões de projeção no DynamoDB
<a name="Expressions.ProjectionExpressions"></a>

Para ler dados de uma tabela, você pode usar operações como `GetItem`, `Query`ou `Scan`. O Amazon DynamoDB retornará todos os atributos de item por padrão. Para obter somente alguns, em vez de todos os atributos, use uma expressão de projeção.

Uma *expressão de projeção* é uma string que identifica os atributos que você deseja. Para recuperar um único atributo, especifique o seu nome. Para vários atributos, os nomes devem ser separados por vírgulas.

Veja a seguir alguns exemplos de expressões de projeção, com base no item do `ProductCatalog` em [Referir-se a atributos de item ao usar expressões no DynamoDB](Expressions.Attributes.md):
+ Um único atributo de nível superior.

  `Title `
+ Três atributos de nível superior. O DynamoDB recupera o conjunto `Color` inteiro.

  `Title, Price, Color`
+ Quatro atributos de nível superior. O DynamoDB retorna todo o conteúdo de `RelatedItems` e `ProductReviews`.

  `Title, Description, RelatedItems, ProductReviews`

**nota**  
A expressão de projeção não afeta o consumo de throughput provisionado. O DynamoDB determina as unidades de capacidade consumidas com base no tamanho do item, e não na quantidade de dados que são retornados para uma aplicação.

**Palavras reservadas e caracteres especiais**

O DynamoDB inclui palavras reservadas e caracteres especiais. O DynamoDB permite usar essas palavras reservadas e caracteres especiais nos nomes, mas é recomendável evitar, pois será necessário usar aliases sempre que esses nomes forem utilizados em uma expressão. Para obter uma lista completa, consulte [Palavras reservadas no DynamoDB](ReservedWords.md).

Você precisará usar nomes de atributo de expressão no lugar do nome real se: 
+ O nome do atributo estiver na lista de palavras reservadas do DynamoDB.
+ O nome do atributo não atender ao requisito de que o primeiro caractere deve ser `a-z` ou `A-Z` e que o segundo caractere (se houver) deve ser `a-Z`, `A-Z` ou `0-9`.
+ O nome do atributo contiver **\$1** (cerquilha) ou **:** (dois-pontos).

O exemplo de AWS CLI a seguir mostra como usar uma expressão de projeção com uma operação `GetItem`. Essa expressão de projeção recupera um atributo escalar de nível superior (`Description`), o primeiro elemento em uma lista (`RelatedItems[0]`) e uma lista aninhada em um mapa (`ProductReviews.FiveStar`).

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '"Id": { "N": "123" } \
    --projection-expression "Description, RelatedItems[0], ProductReviews.FiveStar"
```

O JSON a seguir seria retornado para este exemplo.

```
{
    "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"
                }
            ]
        }
    }
}
```

# Usar expressões de atualização no DynamoDB
<a name="Expressions.UpdateExpressions"></a>

A ação `UpdateItem` atualiza um item existente ou adiciona um item novo à tabela, caso ele ainda não exista. Você deve fornecer a chave do item que deseja atualizar. Você também deve fornecer uma expressão de atualização indicando os atributos que deseja modificar e os valores que deseja atribuir a eles. 

Uma *expressão de atualização* especifica como `UpdateItem` modificará os atributos de um item. Por exemplo, definindo um valor escalar ou removendo elementos de uma lista ou de um mapa.

Veja a seguir um resumo da sintaxe para expressões de atualização.

```
update-expression ::=
    [ SET action [, action] ... ]
    [ REMOVE action [, action] ...]
    [ ADD action [, action] ... ]
    [ DELETE action [, action] ...]
```

Uma expressão de atualização consiste em uma ou mais cláusulas. Cada cláusula começa com uma palavra-chave `SET`, `REMOVE`, `ADD` ou `DELETE`. Você pode incluir qualquer uma dessas cláusulas em uma expressão de atualização, em qualquer ordem. No entanto, cada palavra-chave de ação pode aparecer apenas uma vez.

Dentro de cada cláusula há uma ou mais ações, separadas por vírgulas. Cada ação representa uma modificação de dados.

Os exemplos desta seção se baseiam no item `ProductCatalog` mostrado em [Usar expressões de projeção no DynamoDB](Expressions.ProjectionExpressions.md).

Os tópicos abaixo abrangem alguns casos de uso diferentes da ação `SET`.

**Topics**
+ [SET: modificar ou adicionar atributos de um item](#Expressions.UpdateExpressions.SET)
+ [REMOVE: excluir atributos de um item](#Expressions.UpdateExpressions.REMOVE)
+ [ADD: atualizar números e conjuntos](#Expressions.UpdateExpressions.ADD)
+ [DELETE: remover elementos de um conjunto](#Expressions.UpdateExpressions.DELETE)
+ [Usar várias expressões de atualização](#Expressions.UpdateExpressions.Multiple)

## SET: modificar ou adicionar atributos de um item
<a name="Expressions.UpdateExpressions.SET"></a>

Use a ação `SET` em uma expressão de atualização para adicionar um ou mais atributos a um item. Se qualquer um desses atributos já existir, eles serão substituídos pelos novos valores. Se você deseja evitar a substituição de um atributo existente, pode usar `SET` com a função `if_not_exists`. A função `if_not_exists` é específica à ação `SET` e só pode ser usada em uma expressão de atualização.

Quando você usa `SET` para atualizar um elemento de lista, o conteúdo desse elemento é substituído pelos novos dados especificados. Se o elemento ainda não existir, `SET` acrescentará o novo elemento ao final da lista.

Se você adicionar vários elementos em uma única operação `SET`, estes serão classificados por número de elemento.

Você também pode usar `SET` para adicionar ou subtrair de um atributo do tipo `Number`. Para executar várias ações `SET`, separe-as com vírgulas.

No seguinte resumo de sintaxe:
+ O elemento *path* é o caminho do documento para o item.
+ Um elemento **operando** pode ser o caminho de um documento para um item ou uma função.

```
set-action ::=
    path = value

value ::=
    operand
    | operand '+' operand
    | operand '-' operand

operand ::=
    path | function

function ::=
    if_not_exists (path, value)
```

Se o item não contiver um atributo no caminho especificado, `if_not_exists` será avaliado como `value`. Caso contrário, será avaliado como `path`.

A seguinte operação `PutItem` cria um item de exemplo ao qual os exemplos fazem referência.

```
aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json
```

Os argumentos de `--item` são armazenados no arquivo `item.json`. (Para simplificar, apenas alguns atributos de item são usados.)

```
{
    "Id": {"N": "789"},
    "ProductCategory": {"S": "Home Improvement"},
    "Price": {"N": "52"},
    "InStock": {"BOOL": true},
    "Brand": {"S": "Acme"}
}
```

**Topics**
+ [Modificar atributos](#Expressions.UpdateExpressions.SET.ModifyingAttributes)
+ [Adicionar listas e mapas](#Expressions.UpdateExpressions.SET.AddingListsAndMaps)
+ [Adicionar elementos a uma lista](#Expressions.UpdateExpressions.SET.AddingListElements)
+ [Adicionar atributos de mapa aninhados](#Expressions.UpdateExpressions.SET.AddingNestedMapAttributes)
+ [Incrementar e reduzir atributos numéricos](#Expressions.UpdateExpressions.SET.IncrementAndDecrement)
+ [Acrescentar elementos a uma lista](#Expressions.UpdateExpressions.SET.UpdatingListElements)
+ [Impedir substituições de um atributo existente](#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites)

### Modificar atributos
<a name="Expressions.UpdateExpressions.SET.ModifyingAttributes"></a>

**Example**  
Atualize os atributos `ProductCategory` e `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
```
Os argumentos de `--expression-attribute-values` são armazenados no arquivo `values.json`.  

```
{
    ":c": { "S": "Hardware" },
    ":p": { "N": "60" }
}
```

**nota**  
Na operação `UpdateItem`, `--return-values ALL_NEW` faz com que o DynamoDB retorne o item como ele aparece após a atualização.

### Adicionar listas e mapas
<a name="Expressions.UpdateExpressions.SET.AddingListsAndMaps"></a>

**Example**  
Adicione uma nova lista e um novo mapa.  

```
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
```
Os argumentos de `--expression-attribute-values` são armazenados no arquivo `values.json`.  

```
{
    ":ri": {
        "L": [
            { "S": "Hammer" }
        ]
    },
    ":pr": {
        "M": {
            "FiveStar": {
                "L": [
                    { "S": "Best product ever!" }
                ]
            }
        }
    }
}
```

### Adicionar elementos a uma lista
<a name="Expressions.UpdateExpressions.SET.AddingListElements"></a>

**Example**  
Adicione um novo atributo à lista `RelatedItems`. (Lembre-se de que elementos de lista são baseados em zero e, portanto, [0] representa o primeiro elemento da lista, [1] representa o segundo, e assim por diante.)  

```
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
```
Os argumentos de `--expression-attribute-values` são armazenados no arquivo `values.json`.  

```
{
    ":ri": { "S": "Nails" }
}
```

**nota**  
Quando você usa `SET` para atualizar um elemento de lista, o conteúdo desse elemento é substituído pelos novos dados especificados. Se o elemento ainda não existir, `SET` acrescentará o novo elemento ao final da lista.  
Se você adicionar vários elementos em uma única operação `SET`, estes serão classificados por número de elemento.

### Adicionar atributos de mapa aninhados
<a name="Expressions.UpdateExpressions.SET.AddingNestedMapAttributes"></a>

**Example**  
Adicione alguns atributos de mapa aninhados.  

```
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
```
Os argumentos de `--expression-attribute-names` são armazenados no arquivo `names.json`.  

```
{
    "#pr": "ProductReviews",
    "#5star": "FiveStar",
    "#3star": "ThreeStar"
}
```
Os argumentos de `--expression-attribute-values` são armazenados no arquivo `values.json`.  

```
{
    ":r5": { "S": "Very happy with my purchase" },
    ":r3": {
        "L": [
            { "S": "Just OK - not that great" }
        ]
    }
}
```

**Importante**  
Não será possível atualizar os atributos do mapa aninhado se o mapa pai não existir. Se você tentar atualizar um atributo aninhado (por exemplo, `ProductReviews.FiveStar`) quando o mapa pai (`ProductReviews`) não existir, o DynamoDB exibirá `ValidationException` com a mensagem *“O caminho do documento fornecido na expressão de atualização é inválido para atualização”*.  
Ao criar itens que terão atributos de mapa aninhados atualizados posteriormente, inicialize mapas vazios para os atributos principais. Por exemplo:  

```
{
    "Id": {"N": "789"},
    "ProductReviews": {"M": {}},
    "Metadata": {"M": {}}
}
```
Isso permite que você atualize atributos aninhados, como `ProductReviews.FiveStar`, sem erros.

### Incrementar e reduzir atributos numéricos
<a name="Expressions.UpdateExpressions.SET.IncrementAndDecrement"></a>

Você pode adicionar ou subtrair de um atributo numérico existente. Para fazer isso, use os operadores `+` (mais) e `-` (menos).

**Example**  
Diminua o valor do `Price` de um 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
```
Para aumentar o valor do `Price`, você usa o operador `+` na expressão de atualização.

### Acrescentar elementos a uma lista
<a name="Expressions.UpdateExpressions.SET.UpdatingListElements"></a>

É possível adicionar elementos ao final de uma lista. Para fazer isso, use `SET` com a função `list_append`. (O nome da função diferencia maiúsculas de minúsculas.) A função `list_append` é específica à ação `SET` e só pode ser usada em uma expressão de atualização. A sintaxe é a seguinte.
+ `list_append (list1, list2)`

A função utiliza duas listas como entrada e acrescenta todos os elementos de `list2` a ` list1`.

**Example**  
Em [Adicionar elementos a uma lista](#Expressions.UpdateExpressions.SET.AddingListElements), você cria a lista `RelatedItems` e a preenche com dois elementos: `Hammer` e `Nails`. Na sequência, você acrescenta mais dois elementos ao final de `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
```
Os argumentos de `--expression-attribute-values` são armazenados no arquivo `values.json`.  

```
{
    ":vals": {
        "L": [
            { "S": "Screwdriver" },
            {"S": "Hacksaw" }
        ]
    }
}
```
Por fim, você acrescenta mais um elemento ao *início* de `RelatedItems`. Para fazer isso, alterne a ordem dos elementos de `list_append`. (Lembre-se de que `list_append` usa duas listas como entrada e acrescenta a segunda lista à primeira.)  

```
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
```
Agora, o atributo `RelatedItems` resultante contém cinco elementos, na seguinte ordem: `Chisel`, `Hammer`, `Nails`, `Screwdriver`, `Hacksaw`.

### Impedir substituições de um atributo existente
<a name="Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites"></a>

**Example**  
Defina o `Price` de um item, mas somente se o item ainda não tiver um atributo `Price`. (Se o atributo `Price` já existir, não acontecerá nada.)  

```
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: excluir atributos de um item
<a name="Expressions.UpdateExpressions.REMOVE"></a>

Use a ação `REMOVE` em uma expressão de atualização para remover um ou mais atributos de um item no Amazon DynamoDB. Para executar várias ações `REMOVE`, separe-as com vírgulas.

O seguinte é um resumo da sintaxe de `REMOVE` em uma expressão de atualização. O único operando é o caminho do documento do atributo que você deseja remover.

```
remove-action ::=
    path
```

**Example**  
Remova alguns atributos de um item. (Se os atributos não existirem, nada acontecerá.)  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "REMOVE Brand, InStock, QuantityOnHand" \
    --return-values ALL_NEW
```

### Remover elementos de uma lista
<a name="Expressions.UpdateExpressions.REMOVE.RemovingListElements"></a>

É possível usar `REMOVE` para excluir elementos individuais de uma lista.

**Example**  
Em [Acrescentar elementos a uma lista](#Expressions.UpdateExpressions.SET.UpdatingListElements), você modifica um atributo da lista (`RelatedItems`) de forma que ele contenha cinco elementos:   
+ `[0]`—`Chisel`
+ `[1]`—`Hammer`
+ `[2]`—`Nails`
+ `[3]`—`Screwdriver`
+ `[4]`—`Hacksaw`
O exemplo da AWS Command Line Interface (AWS CLI) a seguir exclui `Hammer` e `Nails` da lista.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "REMOVE RelatedItems[1], RelatedItems[2]" \
    --return-values ALL_NEW
```
Depois que `Hammer` e `Nails` forem removidos, os elementos restantes serão deslocados. Agora, a lista contém o seguinte:  
+ `[0]`—`Chisel`
+ `[1]`—`Screwdriver`
+ `[2]`—`Hacksaw`

## ADD: atualizar números e conjuntos
<a name="Expressions.UpdateExpressions.ADD"></a>

**nota**  
Em geral, recomendamos usar `SET` em vez de `ADD` para garantir operações idempotentes.

Use a ação `ADD` em uma expressão de atualização para adicionar um novo atributo e seus valores a um item.

Se o atributo já existir, o comportamento de `ADD` dependerá do tipo de dados do atributo:
+ Se o atributo for um número, e o valor que você está adicionando também for um número, esse valor será matematicamente adicionado ao atributo existente. (Se o valor for um número negativo, ele será subtraído do atributo existente.)
+ Se o atributo for um conjunto, e o valor que você está adicionando também for um conjunto, esse valor será acrescentado ao conjunto existente.

**nota**  
A ação `ADD` oferece suporte apenas a tipos de dados de número e conjunto.

Para executar várias ações `ADD`, separe-as com vírgulas.

No seguinte resumo de sintaxe:
+ O elemento *path* é o caminho do documento para um atributo. O atributo deve ser um `Number` ou um tipo de dados de conjunto. 
+ O elemento *value* é um número que você deseja adicionar ao atributo (para tipos de dados `Number`) ou um conjunto a ser acrescentado ao atributo (para tipos de conjunto).

```
add-action ::=
    path value
```

Os tópicos abaixo abrangem alguns casos de uso diferentes da ação `ADD`.

**Topics**
+ [Adicionar um número](#Expressions.UpdateExpressions.ADD.Number)
+ [Adicionar elementos a um conjunto](#Expressions.UpdateExpressions.ADD.Set)

### Adicionar um número
<a name="Expressions.UpdateExpressions.ADD.Number"></a>

Suponha que o atributo `QuantityOnHand` não exista. O exemplo da AWS CLI a seguir define `QuantityOnHand` como 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
```

Agora que `QuantityOnHand` existe, você pode executar novamente o exemplo para incrementar `QuantityOnHand` em 5 de cada vez.

### Adicionar elementos a um conjunto
<a name="Expressions.UpdateExpressions.ADD.Set"></a>

Suponha que o atributo `Color` não exista. O exemplo da AWS CLI a seguir define `Color` como um conjunto de strings com dois elementos.

```
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
```

Agora que `Color` existe, você pode adicionar mais elementos a ele.

```
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: remover elementos de um conjunto
<a name="Expressions.UpdateExpressions.DELETE"></a>

**Importante**  
A ação `DELETE` oferece suporte apenas a tipos de dados `Set`.

Use a ação `DELETE` em uma expressão de atualização para remover um ou mais elementos de um conjunto. Para executar várias ações `DELETE`, separe-as com vírgulas.

No seguinte resumo de sintaxe:
+ O elemento *path* é o caminho do documento para um atributo. Esse atributo deve ser um tipo de dados de conjunto.
+ O elemento *subset* é um ou mais elementos que você deseja excluir de *path*. Você deve especificar o elemento *subset* como um tipo set.

```
delete-action ::=
    path subset
```

**Example**  
Em [Adicionar elementos a um conjunto](#Expressions.UpdateExpressions.ADD.Set), você cria o conjunto de tipo string `Color`. Este exemplo remove alguns dos elementos desse conjunto.  

```
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
```

## Usar várias expressões de atualização
<a name="Expressions.UpdateExpressions.Multiple"></a>

É possível usar várias ações em uma única expressão de atualização. Todas as referências a atributos são resolvidas em relação ao estado do item antes que qualquer uma das ações seja aplicada.

**Example**  
Dado um item `{"id": "1", "a": 1, "b": 2, "c": 3}`, a seguinte expressão remove `a` e muda os valores de `b` e `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
```
O resultado é `{"id": "1", "b": 1, "c": 2}`. Embora `a` seja removida e `b` reatribuída na mesma expressão, ambas as referências retornam os valores originais.

**Example**  
Se quiser modificar o valor de um atributo e remover outro completamente, você poderá usar uma ação SET e uma REMOVE em uma única declaração. Essa operação reduziria o valor de `Price` para 15 e, ao mesmo tempo, removeria o atributo `InStock` do 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**  
Se quiser adicionar a uma lista e, ao mesmo tempo, alterar o valor de outro atributo, você poderá usar duas ações SET em uma única declaração. Essa operação adicionaria “Unhas” ao atributo da lista `RelatedItems` e também definiria o valor de `Price` como 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
```

# Expressões de condição e filtro, operadores e funções no DynamoDB
<a name="Expressions.OperatorsAndFunctions"></a>

Para manipular dados em uma tabela do DynamoDB, use as operações `PutItem`, `UpdateItem` e `DeleteItem`. Para essas operações de manipulação de dados, é possível especificar uma expressão de condição para determinar quais itens devem ser modificados. Se a expressão de condição for avaliada como verdadeira, a operação terá êxito. Caso contrário, haverá falha na operação.

Esta seção aborda as funções e palavras-chave integradas para escrever expressões de filtro e expressões de condição no Amazon DynamoDB. Para obter informações mais detalhadas sobre funções e programação com o DynamoDB, consulte [Programação com o DynamoDB e os AWS SDKs](Programming.md) e a [Referência da API do DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/).

**Topics**
+ [Sintaxe para expressões de filtro e de condição](#Expressions.OperatorsAndFunctions.Syntax)
+ [Fazer comparações](#Expressions.OperatorsAndFunctions.Comparators)
+ [Funções](#Expressions.OperatorsAndFunctions.Functions)
+ [Avaliações lógicas](#Expressions.OperatorsAndFunctions.LogicalEvaluations)
+ [Parênteses](#Expressions.OperatorsAndFunctions.Parentheses)
+ [Precedência em condições](#Expressions.OperatorsAndFunctions.Precedence)

## Sintaxe para expressões de filtro e de condição
<a name="Expressions.OperatorsAndFunctions.Syntax"></a>

No seguinte resumo de sintaxe, um *operando* pode ser o seguinte: 
+ Um nome de atributo de nível superior, como `Id`, `Title`, `Description` ou `ProductCategory`
+ Um caminho de documento que faz referência a um atributo aninhado

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

## Fazer comparações
<a name="Expressions.OperatorsAndFunctions.Comparators"></a>

Use esses comparadores para comparar um operando com um único valor:
+ `a = b`: verdadeiro se *a* for igual a *b*.
+ `a <> b`: verdadeiro se *a* não for igual a *b*.
+ `a < b`: verdadeiro se *a* for menor que *b*.
+ `a <= b`: verdadeiro se *a* for menor que ou igual a *b*.
+ `a > b`: verdadeiro se *a* for maior que *b*.
+ `a >= b`: verdadeiro se *a* for maior ou igual a *b*.

Use as palavras-chave `BETWEEN` e `IN` para comparar um operando com um intervalo de valores ou com uma lista enumerada de valores:
+ `a BETWEEN b AND c`: verdadeiro se *a* for maior ou igual a *b* e menor ou igual a *c*.
+ `a IN (b, c, d) `: verdadeiro se *a* for igual a qualquer um dos valores na lista; por exemplo, *b*, *c* ou *d*. A lista pode conter até 100 valores, separados por vírgulas.

## Funções
<a name="Expressions.OperatorsAndFunctions.Functions"></a>

Use as funções a seguir para determinar se um atributo existe em um item ou para avaliar o valor de um atributo. Esses nomes de funções diferenciam maiúsculas de minúsculas. Para um atributo aninhado, você deve fornecer o caminho completo do documento.


****  

| Função | Descrição | 
| --- | --- | 
|  `attribute_exists (path)`  | True se o item contiver o atributo especificado por `path`. Exemplo: verificar se um item na tabela `Product` tem uma imagem de vista lateral. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 
|  `attribute_not_exists (path)`  | True se o atributo especificado por `path` não existir no item. Exemplo: verificar se um item tem um atributo `Manufacturer`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 
|  `attribute_type (path, type)`  |  True se o atributo no caminho especificado for de um tipo de dados específico. O parâmetro `type` deve ser um dos seguintes: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Você deve usar um valor de atributo de expressão para o parâmetro `type`. Exemplo: verificar se o atributo `QuantityOnHand` é do tipo Lista. Neste exemplo, `:v_sub` é um espaço reservado para a string `L`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Você deve usar um valor de atributo de expressão para o parâmetro `type`.   | 
|  `begins_with (path, substr)`  |  Verdadeiro se o atributo especificado por `path` começar com uma substring específica. Exemplo: verificar se os primeiros caracteres do URL da imagem de vista frontal são `http://`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) O valor do atributo de expressão `:v_sub` é um espaço reservado para `http://`.  | 
|  `contains (path, operand)`  | Verdadeiro se o atributo especificado por `path` for um dos seguintes: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Se o atributo especificado por `path` for `String`, o `operand` deve ser `String`. Se o atributo especificado por `path` for um `Set`, o `operand` deverá ser o tipo de elemento do conjunto. O caminho e o operando devem ser distintos. Isto é, `contains (a, a)` retorna um erro. Exemplo: verificar se o atributo `Brand` contém a substring `Company`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) O valor do atributo de expressão `:v_sub` é um espaço reservado para `Company`. Exemplo: verificar se o produto está disponível em vermelho. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) O valor do atributo de expressão `:v_sub` é um espaço reservado para `Red`. | 
|  `size (path)`  | Retorna um número que representa o tamanho de um atributo. Veja a seguir os tipos de dados válidos para uso com `size`.  Se o atributo for do tipo `String`, `size` retornará o comprimento da string. Exemplo: verificar se a string `Brand` é menor ou igual a 20 caracteres. O valor do atributo de expressão `:v_sub` é um espaço reservado para `20`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  Se o atributo for do tipo `Binary`, `size` retornará o número de bytes no valor do atributo. Exemplo: suponha que o item de `ProductCatalog` tenha um atributo binário chamado `VideoClip`, que contém um curto vídeo sobre o produto em uso. A seguinte expressão verifica se `VideoClip` excede 64.000 bytes. O valor do atributo de expressão `:v_sub` é um espaço reservado para `64000`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  Se o atributo for de um tipo de dados de `Set`, `size` retornará o número de elementos no conjunto.  Exemplo: verificar se o produto está disponível em mais de uma cor. O valor do atributo de expressão `:v_sub` é um espaço reservado para `1`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  Se o atributo for do tipo `List` ou `Map`, `size` retornará o número de elementos filho. Exemplo: verificar se o número de revisões `OneStar` excedeu um determinado limite. O valor do atributo de expressão `:v_sub` é um espaço reservado para `3`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 

## Avaliações lógicas
<a name="Expressions.OperatorsAndFunctions.LogicalEvaluations"></a>

Use as palavras-chave `AND`, `OR` e `NOT` para executar avaliações lógicas. Na lista a seguir, *a* e *b* representam condições a serem avaliadas.
+ `a AND b`: verdadeiro se *a* e *b* forem ambos verdadeiros.
+ `a OR b`: verdadeiro se *a* ou *b* ou ambos forem verdadeiros.
+ `NOT a`: verdadeiro se *a* for falso. Falso se *a* for verdadeiro.

Veja a seguir um exemplo de código de AND em uma operação.

`dynamodb-local (*)> select * from exprtest where a > 3 and a < 5;`

## Parênteses
<a name="Expressions.OperatorsAndFunctions.Parentheses"></a>

Use parênteses para alterar a precedência de uma avaliação lógica. Por exemplo, suponha que as condições *a* e *b* sejam verdadeiras e que a condição *c* seja falsa. As expressões a seguir são avaliadas como verdadeiras:
+ `a OR b AND c`

No entanto, se você colocar uma condição entre parênteses, ela será avaliada primeiro. Por exemplo, o seguinte é avaliado como falso:
+  `(a OR b) AND c`

**nota**  
Você pode aninhar parênteses em uma expressão. Os componentes mais internos são avaliados primeiro.

Veja a seguir um exemplo de código com parênteses em uma avaliação lógica.

`dynamodb-local (*)> select * from exprtest where attribute_type(b, string) or ( a = 5 and c = “coffee”);`

## Precedência em condições
<a name="Expressions.OperatorsAndFunctions.Precedence"></a>

 O DynamoDB avalia as condições da esquerda para a direita usando as seguintes regras de precedência:
+ `= <> < <= > >=`
+ `IN`
+ `BETWEEN`
+ `attribute_exists attribute_not_exists begins_with contains`
+ Parênteses
+ `NOT`
+ `AND`
+ `OR`

# Exemplo de expressão de condição do DynamoDB na CLI
<a name="Expressions.ConditionExpressions"></a>

Veja a seguir alguns exemplos da AWS Command Line Interface (AWS CLI) para uso de expressões de condição. Estes exemplos se baseiam na tabela `ProductCatalog`, que foi apresentada em [Referir-se a atributos de item ao usar expressões no DynamoDB](Expressions.Attributes.md). A chave de partição dessa tabela é `Id`. Não há uma chave de classificação. A seguinte operação `PutItem` cria um item `ProductCatalog` de amostra ao qual os exemplos se referem.

```
aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json
```

Os argumentos de `--item` são armazenados no arquivo `item.json`. (Para simplificar, apenas alguns atributos de item são usados.)

```
{
    "Id": {"N": "456" },
    "ProductCategory": {"S": "Sporting Goods" },
    "Price": {"N": "650" }
}
```

**Topics**
+ [Put condicional](#Expressions.ConditionExpressions.PreventingOverwrites)
+ [Exclusões condicionais](#Expressions.ConditionExpressions.AdvancedComparisons)
+ [Atualizações condicionais](#Expressions.ConditionExpressions.SimpleComparisons)
+ [Exemplos de expressão condicional](#Expressions.ConditionExpressions.ConditionalExamples)

## Put condicional
<a name="Expressions.ConditionExpressions.PreventingOverwrites"></a>

A operação `PutItem` substitui um item com a mesma chave primária (se houver). Se quiser evitar isso, use uma expressão de condição. Isso permitirá que a gravação continue apenas se o item em questão ainda não tiver a mesma chave primária.

O exemplo a seguir usa `attribute_not_exists()` para verificar se a chave primária existe na tabela antes de tentar a operação de gravação. 

**nota**  
Se a chave primária consistir em uma chave de partição (pk) e uma chave de classificação (sk), o parâmetro verificará se `attribute_not_exists(pk)` E `attribute_not_exists(sk)` são avaliados como uma declaração inteiramente verdadeira ou falsa antes de tentar a operação de gravação.

```
aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json \
    --condition-expression "attribute_not_exists(Id)"
```

Se a expressão de condição for avaliada como falsa, o DynamoDB retornará uma mensagem de erro The conditional request failed (Falha na solicitação condicional).

**nota**  
Para obter mais informações sobre `attribute_not_exists` e outras funções, consulte [Expressões de condição e filtro, operadores e funções no DynamoDB](Expressions.OperatorsAndFunctions.md).

## Exclusões condicionais
<a name="Expressions.ConditionExpressions.AdvancedComparisons"></a>

Para realizar uma exclusão condicional, use uma operação `DeleteItem` com uma expressão de condição. A expressão de condição deve ser avaliada como verdadeira para que a operação tenha êxito; caso contrário, haverá falha na operação.

Considere o item definido acima.

Suponha que você queira excluir o item, mas somente nas seguintes condições:
+  O valor de `ProductCategory` é “Sporting Goods” ou “Gardening Supplies”.
+  O valor de `Price` está entre 500 e 600.

O exemplo a seguir tenta excluir o 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
```

Os argumentos de `--expression-attribute-values` são armazenados no arquivo `values.json`.

```
{
    ":cat1": {"S": "Sporting Goods"},
    ":cat2": {"S": "Gardening Supplies"},
    ":lo": {"N": "500"},
    ":hi": {"N": "600"}
}
```

**nota**  
Na expressão de condição, o caractere `:` (dois pontos) indica um *valor de atributo de expressão*: um espaço reservado para um valor real. Para obter mais informações, consulte [Usar valores de atributos de expressão no DynamoDB](Expressions.ExpressionAttributeValues.md).  
Para obter mais informações sobre `IN`, `AND` e outras palavras-chave, consulte [Expressões de condição e filtro, operadores e funções no DynamoDB](Expressions.OperatorsAndFunctions.md).

Neste exemplo, a comparação `ProductCategory` é avaliada como true, mas a comparação `Price` é avaliada como false. Isso faz com que a expressão de condição seja avaliada como falsa e haja falha na operação `DeleteItem`.

## Atualizações condicionais
<a name="Expressions.ConditionExpressions.SimpleComparisons"></a>

Para realizar uma atualização condicional, use uma operação `UpdateItem` com uma expressão de condição. A expressão de condição deve ser avaliada como verdadeira para que a operação tenha êxito. Caso contrário, haverá falha na operação.

**nota**  
`UpdateItem` também oferece suporte a *expressões de atualização*, nas quais você especifica as modificações que deseja fazer em um item. Para obter mais informações, consulte [Usar expressões de atualização no DynamoDB](Expressions.UpdateExpressions.md).

Suponha que você tenha começado com o item definido acima.

O exemplo a seguir realiza uma operação `UpdateItem`. Ele tenta reduzir o `Price` de um produto em 75, mas a expressão de condição impedirá a atualização se o `Price` atual for menor ou igual a 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
```

Os argumentos de `--expression-attribute-values` são armazenados no arquivo `values.json`.

```
{
    ":discount": { "N": "75"},
    ":limit": {"N": "500"}
}
```

Se o valor inicial de `Price` for 650, a operação `UpdateItem` reduzirá o `Price` para 575. Se você executar a operação `UpdateItem` novamente, o valor de `Price` será reduzido para 500. Se você executá-la uma terceira vez, a expressão de condição será avaliada como falsa, e haverá falha na atualização.

**nota**  
Na expressão de condição, o caractere `:` (dois pontos) indica um *valor de atributo de expressão*: um espaço reservado para um valor real. Para obter mais informações, consulte [Usar valores de atributos de expressão no DynamoDB](Expressions.ExpressionAttributeValues.md).  
Para obter mais informações sobre "*>*" e outros operadores, consulte [Expressões de condição e filtro, operadores e funções no DynamoDB](Expressions.OperatorsAndFunctions.md).

## Exemplos de expressão condicional
<a name="Expressions.ConditionExpressions.ConditionalExamples"></a>

Para obter mais informações sobre as funções usadas nos exemplos a seguir, consulte [Expressões de condição e filtro, operadores e funções no DynamoDB](Expressions.OperatorsAndFunctions.md). Se você quiser saber mais sobre como especificar diferentes tipos de atributo em uma expressão, consulte [Referir-se a atributos de item ao usar expressões no DynamoDB](Expressions.Attributes.md). 

### Verificar atributos em um item
<a name="Expressions.ConditionExpressions.CheckingForAttributes"></a>

Você pode verificar a existência (ou inexistência) de qualquer atributo. Se a expressão da condição for avaliada como verdadeira, a operação terá êxito. Caso contrário, haverá falha.

O exemplo a seguir usa `attribute_not_exists` para excluir um produto apenas se ele não tiver um atributo `Price`.

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "attribute_not_exists(Price)"
```

O DynamoDB também fornece uma função `attribute_exists`. O exemplo a seguir excluirá um produto somente se ele tiver recebido revisões ruins.

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "attribute_exists(ProductReviews.OneStar)"
```

### Verificar tipo de atributo
<a name="Expressions.ConditionExpressions.CheckingForAttributeType"></a>

É possível verificar o tipo de dados de um valor de atributo usando a função `attribute_type`. Se a expressão da condição for avaliada como verdadeira, a operação terá êxito. Caso contrário, haverá falha.

O exemplo a seguir usa `attribute_type` para excluir um produto somente se ele tiver um atributo `Color` do tipo Conjunto de strings. 

```
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
```

Os argumentos de `--expression-attribute-values` são armazenados no arquivo expression-attribute-values.json.

```
{
    ":v_sub":{"S":"SS"}
}
```

### Verificar valor inicial da string
<a name="Expressions.ConditionExpressions.CheckingBeginsWith"></a>

É possível verificar se um valor de atributo String começa com uma substring específica usando a função `begins_with`. Se a expressão da condição for avaliada como verdadeira, a operação terá êxito. Caso contrário, haverá falha. 

O exemplo a seguir usará `begins_with` para excluir um produto somente se o elemento `FrontView` do mapa `Pictures` começar com um valor específico.

```
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
```

Os argumentos de `--expression-attribute-values` são armazenados no arquivo expression-attribute-values.json.

```
{
    ":v_sub":{"S":"http://"}
}
```

### Verificar um elemento em um conjunto
<a name="Expressions.ConditionExpressions.CheckingForContains"></a>

É possível verificar se há um elemento em um conjunto ou procurar uma substring em uma string usando a função `contains`. Se a expressão da condição for avaliada como verdadeira, a operação terá êxito. Caso contrário, haverá falha. 

O exemplo a seguir usará `contains` para excluir um produto somente se o Conjunto de strings `Color` tiver um elemento com um valor específico. 

```
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
```

Os argumentos de `--expression-attribute-values` são armazenados no arquivo expression-attribute-values.json.

```
{
    ":v_sub":{"S":"Red"}
}
```

### Verificar o tamanho do valor de um atributo
<a name="Expressions.ConditionExpressions.CheckingForSize"></a>

É possível verificar o tamanho do valor de um atributo usando a função `size`. Se a expressão da condição for avaliada como verdadeira, a operação terá êxito. Caso contrário, haverá falha. 

O exemplo a seguir usará `size` para excluir um produto somente se o tamanho do atributo binário `VideoClip` for maior que `64000` bytes. 

```
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
```

Os argumentos de `--expression-attribute-values` são armazenados no arquivo expression-attribute-values.json.

```
{
    ":v_sub":{"N":"64000"}
}
```

# Usar a vida útil (TTL) no DynamoDB
<a name="TTL"></a>

A vida útil (TTL) para DynamoDB é um método econômico para excluir itens que não são mais relevantes. A TTL permite definir um carimbo de data e hora de validade por item que indica quando um item não é mais necessário. O DynamoDB exclui automaticamente os itens expirados alguns dias após o vencimento, sem consumir o throughput de gravação. 

Para usar a TTL, primeiro habilite-a em uma tabela e, depois, defina um atributo específico para armazenar o carimbo de data e hora de vencimento da TTL. O carimbo de data/hora deve ser armazenado como um tipo de dados de [número](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes) no [formato de hora de época do Unix](https://en.wikipedia.org/wiki/Unix_time) na granularidade de segundos. Itens com um atributo TTL que não seja do tipo de número são ignorados pelo processo TTL. Sempre que um item é criado ou atualizado, é possível calcular o prazo de validade e salvá-lo no atributo TTL.

Itens com atributos TTL válidos e expirados podem ser excluídos pelo sistema a qualquer momento, normalmente alguns dias após a validade. Você ainda pode atualizar os itens expirados que estão pendentes de exclusão, incluindo alterar ou remover os atributos TTL. Ao atualizar um item expirado, recomendamos usar uma expressão de condição para garantir que o item não tenha sido excluído posteriormente. Use expressões de filtro para remover itens expirados dos resultados de [Scan](Scan.md#Scan.FilterExpression) e [Query](Query.FilterExpression.md).

Os itens excluídos funcionam de forma semelhante aos excluídos por meio de operações de exclusão típicas. Depois de excluídos, os itens entram no DynamoDB Streams como exclusões de serviços, em vez de exclusões de usuários, e são removidos dos índices secundários locais e globais, assim como outras operações de exclusão. 

Se estiver usando [Global Tables versão 2019.11.21 (atual)](GlobalTables.md) das tabelas globais e também usar o recurso TTL, o DynamoDB replicará as exclusões de TTL em todas as tabelas de réplica. A exclusão inicial de TTL não consome unidades de capacidade de gravação (WCU) na região onde a TTL expira. No entanto, a exclusão de TTL replicada para as tabelas de réplica consume uma unidade de capacidade de gravação replicada ao usar a capacidade provisionada ou a unidade de gravação replicada ao usar o modo de capacidade sob demanda, em cada uma das regiões de réplica, e serão aplicadas cobranças.

Para obter mais informações sobre TTL, consulte estes tópicos:

**Topics**
+ [Habilitar a vida útil (TTL) no DynamoDB](time-to-live-ttl-how-to.md)
+ [Como calcular a vida útil (TTL) no DynamoDB](time-to-live-ttl-before-you-start.md)
+ [Trabalhar com itens expirados e vida útil (TTL)](ttl-expired-items.md)

# Habilitar a vida útil (TTL) no DynamoDB
<a name="time-to-live-ttl-how-to"></a>

**nota**  
Para auxiliar na depuração e verificação da operação adequada do recurso TTL, os valores fornecidos para o item TTL são registrados em log em texto simples nos logs de diagnóstico do DynamoDB.

É possível habilitar a TTL no console do Amazon DynamoDB, na AWS Command Line Interface (AWS CLI) ou usando a [Referência da API do Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/) com qualquer um dos supostos SDKs da AWS. Demora cerca de uma hora para que a TTL seja habilitada em todas as partições.

## Habilitar a TTL do DynamoDB usando o console da AWS
<a name="time-to-live-ttl-how-to-enable-console"></a>

1. Faça login no Console de gerenciamento da AWS e abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/).

1. Escolha **Tables (Tabelas)** e selecione a tabela que você deseja modificar.

1. Na guia **Configurações adicionais**, na seção **Vida útil (TTL)**, selecione **Ativar** para habilitar a TTL.

1. Ao habilitar o TTL em uma tabela, o DynamoDB exige identificar um nome de atributo específico que o serviço procurará ao determinar se um item está qualificado para expiração. O nome do atributo TTL, mostrado abaixo, diferencia maiúsculas de minúsculas e deve corresponder ao atributo definido em suas operações de leitura e gravação. Uma incompatibilidade fará com que os itens expirados não sejam excluídos. Para renomear o atributo TTL, é necessário desabilitar a TTL e a reabilitar com o novo atributo daqui para frente. A TTL continuará processando as exclusões por cerca de trinta minutos depois de desabilitada. A TTL deve ser reconfigurada em tabelas restauradas.  
![\[Nome do atributo TTL com distinção entre maiúsculas e minúsculas que o DynamoDB usa para determinar a elegibilidade de um item para validade.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/EnableTTL-Settings.png)

1. (Opcional) É possível realizar um teste simulando a data e a hora da validade e combinando alguns itens. Isso fornece uma lista de exemplos de itens e confirma que há itens com o nome do atributo TTL fornecido junto com o prazo de validade.

Depois de habilitar a TTL, o atributo TTL é marcado como **TTL** quando você visualiza itens no console do DynamoDB. Você pode visualizar a data e a hora em que um item expira posicionando o mouse sobre o atributo. 

## Habilitar a TTL do DynamoDB usando a API
<a name="time-to-live-ttl-how-to-enable-api"></a>

------
#### [ Python ]

É possível habilitar a TTL com código, usando a operação [UpdateTimeToLive](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/update_time_to_live.html).

```
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')
```

É possível confirmar se a TTL está habilitada usando a operação [DescribeTimeToLive](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/describe_time_to_live.html), que descreve o status da TTL em uma tabela. O status `TimeToLive` é `ENABLED` ou `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 ]

É possível habilitar a TTL com código, usando a operação [UpdateTimeToLiveCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-dynamodb/Class/UpdateTimeToLiveCommand/).

```
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');
```

------

## Habilitar a vida útil usando a AWS CLI
<a name="time-to-live-ttl-how-to-enable-cli-sdk"></a>

1. Habilite o TTL na tabela `TTLExample`.

   ```
   aws dynamodb update-time-to-live --table-name TTLExample --time-to-live-specification "Enabled=true, AttributeName=ttl"
   ```

1. Descreva o TTL na tabela `TTLExample`.

   ```
   aws dynamodb describe-time-to-live --table-name TTLExample
   {
       "TimeToLiveDescription": {
           "AttributeName": "ttl",
           "TimeToLiveStatus": "ENABLED"
       }
   }
   ```

1. Para adicionar um item à tabela `TTLExample` com o conjunto de atributos de vida útil usando o shell BASH e a AWS CLI. 

   ```
   EXP=`date -d '+5 days' +%s`
   aws dynamodb put-item --table-name "TTLExample" --item '{"id": {"N": "1"}, "ttl": {"N": "'$EXP'"}}'
   ```

Este exemplo inicia na data atual e adiciona 5 dias a ela para criar uma data de expiração. Depois, ele converte a data de expiração em formato de hora epoch para finalmente adicionar um item à tabela "`TTLExample`". 

**nota**  
 Uma forma de definir os valores de expiração para a vida útil é calcular o número de segundos para adicionar o tempo de expiração. Por exemplo, 5 dias é igual a 432.000 segundos. No entanto, muitas vezes é preferível começar com uma data e trabalhar a partir desse ponto.

É muito simples obter a hora atual no formato de hora epoch, como nos seguintes exemplos.
+ Terminal Linux: `date +%s`
+ Python: `import time; int(time.time())`
+ Java: `System.currentTimeMillis() / 1000L`
+ JavaScript: : `Math.floor(Date.now() / 1000)`

## Habilitar a TTL do DynamoDB usando o 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
```

Detalhes adicionais sobre o uso do TTL em seus modelos do CloudFormation podem ser encontrados [aqui](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-table-timetolivespecification.html).

# Como calcular a vida útil (TTL) no DynamoDB
<a name="time-to-live-ttl-before-you-start"></a>

Uma forma comum de implementar a TTL é definir um prazo de validade para os itens com base em quando eles foram criados ou atualizados pela última vez. Isso pode ser feito adicionando hora aos carimbos de data e hora `createdAt` e `updatedAt`. Por exemplo, a TTL para itens recém-criados pode ser definida como `createdAt` \$1 noventa dias. Quando o item é atualizado, a TTL pode ser recalculada para `updatedAt` \$1 noventa dias.

O prazo de validade calculado deve estar no formato de época, em segundos. Para ser considerada para validade e exclusão, a TTL não pode ter mais de cinco anos no passado. Se você usar qualquer outro formato, os processos TTL ignorarão o item. Se você definir o prazo de validade como algum momento no futuro em que quiser que o item expire, o item expira após esse horário. Por exemplo, digamos que você defina o prazo de validade como 1724241326 (que é segunda-feira, 21 de agosto de 2024, 11:55:26 (UTC)). O item expira após o horário especificado. Não há duração mínima de TTL. Você pode definir o prazo de validade para qualquer hora futura, como 5 minutos a partir da hora atual. No entanto, o DynamoDB normalmente exclui itens expirados dentro de 48 horas após o prazo de validade, não imediatamente quando o item expira.

**Topics**
+ [Criar um item e definir a vida útil](#time-to-live-ttl-before-you-start-create)
+ [Atualizar um item e atualizar a vida útil](#time-to-live-ttl-before-you-start-update)

## Criar um item e definir a vida útil
<a name="time-to-live-ttl-before-you-start-create"></a>

O exemplo a seguir demonstra como calcular o prazo de validade ao criar um item, usando `expireAt` como nome do atributo TTL. Uma declaração de atribuição exibe a hora atual como uma variável. No exemplo, o prazo de validade é calculado como noventa dias a partir do horário atual. A hora é então convertida no formato de época e salva como um tipo de dados inteiro no atributo TTL.

Os exemplos de código a seguir mostram como criar um item com TTL.

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

**SDK para 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;
        }
    }
}
```
+  Consulte detalhes da API em [PutItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/PutItem) na *Referência da API AWS SDK for Java 2.x*. 

------
#### [ JavaScript ]

**SDK para 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');
```
+  Consulte detalhes da API em [PutItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/PutItemCommand) na *Referência da API AWS SDK para JavaScript*. 

------
#### [ Python ]

**SDK para 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"
)
```
+  Consulte detalhes da API em [PutItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/PutItem) na *Referência da API do AWS SDK para Python (Boto3)*. 

------

## Atualizar um item e atualizar a vida útil
<a name="time-to-live-ttl-before-you-start-update"></a>

Este exemplo é uma continuação do exemplo da [seção anterior](#time-to-live-ttl-before-you-start-create). O prazo de validade poderá ser recalculado se o item for atualizado. O exemplo a seguir recalcula o carimbo de data e hora `expireAt` para ser noventa dias a partir da hora atual.

Os exemplos de código a seguir mostram como atualizar a TTL de um item.

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

**SDK para Java 2.x**  
Atualize a TTL em um item do DynamoDB existente em uma tabela.  

```
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;
        }
    }
```
+  Consulte detalhes da API em [UpdateItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem) na *Referência da API AWS SDK for Java 2.x*. 

------
#### [ JavaScript ]

**SDK para 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');
```
+  Consulte detalhes da API em [UpdateItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/UpdateItemCommand) na *Referência da API AWS SDK para JavaScript*. 

------
#### [ Python ]

**SDK para 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"
)
```
+  Consulte detalhes da API em [UpdateItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/UpdateItem) na *Referência da API AWS SDK para Python (Boto3)*. 

------

Os exemplos de TTL abordados nesta introdução demonstram um método que garante que somente os itens atualizados recentemente sejam mantidos em uma tabela. Os itens atualizados têm sua vida útil estendida, enquanto os itens não atualizados após a criação expiram e são excluídos sem nenhum custo, reduzindo o armazenamento e mantendo as tabelas limpas.

# Trabalhar com itens expirados e vida útil (TTL)
<a name="ttl-expired-items"></a>

Os itens expirados que estão pendentes de exclusão podem ser filtrados das operações de leitura e de gravação. Isso é útil em situações em que os dados expirados não são mais válidos e não devem ser usados. Se não forem filtrados, continuarão sendo exibidos nas operações de leitura e de gravação até serem excluídos pelo processo em segundo plano.

**nota**  
Esses itens ainda contam em relação aos custos de armazenamento e de leitura até serem excluídos.

As exclusões de TTL podem ser identificadas no DynamoDB Streams, mas somente na região em que a exclusão ocorreu. As exclusões de TTL que são replicadas em regiões da tabela global não podem ser identificadas nos fluxos do DynamoDB nas regiões nas quais a exclusão é replicada.

## Filtrar itens expirados das operações de leitura
<a name="ttl-expired-items-filter"></a>

Em relação a operações de leitura, como [Scan](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html) e [Query](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html), uma expressão de filtro pode filtrar itens expirados que estão pendentes de exclusão. Conforme mostrado no trecho de código a seguir, a expressão de filtro pode filtrar itens em que a hora de TTL é igual ou menor que a hora atual. Por exemplo, o código do SDK para Python inclui uma declaração de atribuição que tem a hora atual como uma variável (`now`) e a converte em `int` para o formato de hora de época.

Os exemplos de código a seguir mostram como consultar itens com TTL.

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

**SDK para Java 2.x**  
Use uma expressão filtrada na consulta para reunir os itens com TTL em uma tabela do DynamoDB por meio do 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;
        }
```
+  Consulte detalhes da API em [Query](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/Query) na *Referência da API AWS SDK for Java 2.x*. 

------
#### [ JavaScript ]

**SDK para JavaScript (v3)**  
Use uma expressão filtrada na consulta para reunir os itens com TTL em uma tabela do DynamoDB por meio do AWS SDK para 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');
```
+  Consulte detalhes da API em [Query](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/QueryCommand) na *Referência da API AWS SDK para JavaScript*. 

------
#### [ Python ]

**SDK para Python (Boto3).**  
Use uma expressão filtrada na consulta para reunir os itens com TTL em uma tabela do DynamoDB por meio do AWS SDK para 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")
```
+  Consulte detalhes da API em [Query](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/Query) na *Referência da API AWS SDK para Python (Boto3)*. 

------

## Gravar de modo condicional em itens expirados
<a name="ttl-expired-items-conditional-write"></a>

Uma expressão de condição pode ser usada para evitar gravações em itens expirados. O trecho de código abaixo é uma atualização condicional que confere se o prazo de validade é maior que o horário atual. Se verdadeiro, a operação de gravação continuará.

Os exemplos de código a seguir mostram como atualizar condicionalmente a TTL de um item.

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

**SDK para Java 2.x**  
Atualize a TTL em um item do DynamoDB existente em uma tabela, com uma condição.  

```
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;
        }
    }
}
```
+  Consulte detalhes da API em [UpdateItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem) na *Referência da API AWS SDK for Java 2.x*. 

------
#### [ JavaScript ]

**SDK para JavaScript (v3)**  
Atualize a TTL em um item do DynamoDB existente em uma tabela, com uma condição.  

```
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');
```
+  Consulte detalhes da API em [UpdateItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/UpdateItemCommand) na *Referência da API AWS SDK para JavaScript*. 

------
#### [ Python ]

**SDK para Python (Boto3).**  
Atualize a TTL em um item do DynamoDB existente em uma tabela, com uma condição.  

```
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",
)
```
+  Consulte detalhes da API em [UpdateItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/UpdateItem) na *Referência da API AWS SDK para Python (Boto3)*. 

------

## Identificar itens excluídos no DynamoDB Streams
<a name="ttl-expired-items-identifying"></a>

O registro de fluxos contém um campo de identidade do usuário `Records[<index>].userIdentity`. Os itens excluídos pelo processo do TTL têm os seguintes campos:

```
Records[<index>].userIdentity.type
"Service"

Records[<index>].userIdentity.principalId
"dynamodb.amazonaws.com"
```

O JSON a seguir mostra a parte relevante de um único registro de fluxos.

```
"Records": [ 
  { 
	... 
		"userIdentity": {
		"type": "Service", 
      	"principalId": "dynamodb.amazonaws.com" 
   	} 
   ... 
	} 
]
```

# Consultar tabelas no DynamoDB
<a name="Query"></a>

Você pode usar a operação de API `Query` no Amazon DynamoDB para encontrar itens com base nos valores de chave primária.

Você deve fornecer o nome do atributo de chave de partição e um único valor para esse atributo. A operação `Query` retorna todos os itens com esse valor de chave de partição. Opcionalmente, você pode fornecer um atributo de chave de classificação e usar um operador de comparação para refinar os resultados da pesquisa.

Para obter mais informações sobre como usar `Query`, como a sintaxe de solicitação, parâmetros de resposta e exemplos adicionais, acesse [Consulta](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html) na *Referência da API do Amazon DynamoDB*.

**Topics**
+ [Principais expressões de condição para a operação de consulta no DynamoDB](Query.KeyConditionExpressions.md)
+ [Filtrar expressões para a operação de consulta no DynamoDB](Query.FilterExpression.md)
+ [Paginar os resultados de consultas à tabela no DynamoDB](Query.Pagination.md)
+ [Outros aspectos do trabalho com a operação de consulta no DynamoDB](Query.Other.md)

# Principais expressões de condição para a operação de consulta no DynamoDB
<a name="Query.KeyConditionExpressions"></a>

Você pode usar qualquer nome de atributo em uma expressão de condição principal, desde que o primeiro caractere seja `a-z` ou `A-Z` e o restante dos caracteres (a partir do segundo caractere, se houver) seja `a-z`, `A-Z` ou `0-9`. Além disso, o nome do atributo não deve ser uma palavra reservada do DynamoDB. (Para obter uma lista completa dessas palavras reservadas, consulte [Palavras reservadas no DynamoDB](ReservedWords.md).) Se um nome de atributo não atender a esses requisitos, defina um nome de atributo de expressão como um espaço reservado. Para obter mais informações, consulte [Nomes (aliases) de atributo de expressão no DynamoDB](Expressions.ExpressionAttributeNames.md).

Para itens com um determinado valor de chave de partição, o DynamoDB armazena esses itens juntos em ordem classificada por valor de chave de classificação. Em uma operação `Query`, o DynamoDB recupera os itens na ordem classificada e, em seguida, processa os itens usando `KeyConditionExpression` e qualquer `FilterExpression` que estiver presente. Somente então os resultados de `Query` são enviados de volta para o cliente.

Uma operação `Query` sempre retorna um conjunto de resultados. Se não forem encontrados itens correspondentes, o conjunto de resultados estará vazio.

`Query`Os resultados de são sempre classificados pelo valor de chave de classificação. Se o tipo de dados da chave de classificação for `Number`, os resultados serão retornados em ordem numérica. Caso contrário, os resultados serão retornados na ordem de bytes UTF-8. Por padrão, a ordem de classificação é crescente. Para reverter a ordem, defina o parâmetro `ScanIndexForward` como `false`.

Uma única operação `Query` pode recuperar um máximo de 1 MB de dados. Esse limite se aplica antes de qualquer expressão `FilterExpression` ou `ProjectionExpression` ser aplicada aos resultados. Se `LastEvaluatedKey` estiver presente na resposta e não for nula, você deverá paginar o conjunto de resultados (consulte [Paginar os resultados de consultas à tabela no DynamoDB](Query.Pagination.md)).

## Exemplos das principais expressões de condição
<a name="Query.KeyConditionExpressions-example"></a>

Para especificar os critérios de pesquisa, você deve usar uma *expressão de condição principal* – uma string que determina os itens a serem lidos da tabela ou índice.

Você deve especificar o nome e o valor da chave de partição como uma condição de igualdade. Não é possível usar um atributo que não seja de chave em uma expressão de condição de chave.

Opcionalmente, você pode fornecer uma segunda condição para a chave de classificação (se houver). A condição de chave de classificação deve usar um dos seguintes operadores de comparação:
+ `a = b` - verdadeiro se o atributo *a* for igual ao valor *b*
+ `a < b`: verdadeiro se *a* for menor que *b*
+ `a <= b`: verdadeiro se *a* for menor que ou igual a *b*
+ `a > b`: verdadeiro se *a* for maior que *b*
+ `a >= b`: verdadeiro se *a* for maior ou igual a *b*
+ `a BETWEEN b AND c` - verdadeiro se *a* for maior ou igual a *b*e menor ou igual a *c*.

A função a seguir também tem suporte:
+ `begins_with (a, substr)`- verdadeiro se o valor do atributo `a` começa com uma determinada substring.

Os seguintes exemplos da AWS Command Line Interface (AWS CLI) demonstram o uso das expressões de condição de chave. Essas expressões usam espaços reservados (como `:name` e `:sub`), em vez de valores reais. Para obter mais informações, consulte [Nomes (aliases) de atributo de expressão no DynamoDB](Expressions.ExpressionAttributeNames.md) e [Usar valores de atributos de expressão no DynamoDB](Expressions.ExpressionAttributeValues.md).

**Example**  
Consulte a tabela `Thread` para encontrar um `ForumName` específico (chave de partição). Todos os itens com esse valor de `ForumName` são lidos pela consulta, porque a chave de classificação (`Subject`) não está incluída na `KeyConditionExpression`.  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :name" \
    --expression-attribute-values  '{":name":{"S":"Amazon DynamoDB"}}'
```

**Example**  
Consulte a tabela `Thread` para encontrar um `ForumName` específico (chave de partição), mas, desta vez, retornar apenas os itens com um determinado `Subject` (chave de classificação).  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :name and Subject = :sub" \
    --expression-attribute-values  file://values.json
```
Os argumentos de `--expression-attribute-values` são armazenados no arquivo `values.json`.  

```
{
    ":name":{"S":"Amazon DynamoDB"},
    ":sub":{"S":"DynamoDB Thread 1"}
}
```

**Example**  
Consulte a tabela `Reply` para encontrar um `Id` específico (chave de partição), mas retornar apenas os itens cuja `ReplyDateTime` (chave de classificação) começa com determinados caracteres.  

```
aws dynamodb query \
    --table-name Reply \
    --key-condition-expression "Id = :id and begins_with(ReplyDateTime, :dt)" \
    --expression-attribute-values  file://values.json
```
Os argumentos de `--expression-attribute-values` são armazenados no arquivo `values.json`.  

```
{
    ":id":{"S":"Amazon DynamoDB#DynamoDB Thread 1"},
    ":dt":{"S":"2015-09"}
}
```

# Filtrar expressões para a operação de consulta no DynamoDB
<a name="Query.FilterExpression"></a>

Se você precisar refinar ainda mais os resultados de `Query`, existe a opção de utilizar uma expressão de filtro. Uma *expressão de filtro* determina quais itens dos resultados de `Query` devem ser retornados para você. Todos os outros resultados serão descartados.

Uma expressão de filtro é aplicada depois que uma operação `Query` é concluída, mas antes que os resultados sejam retornados. Portanto, uma operação `Query` consome a mesma quantidade de capacidade de leitura, independentemente de uma expressão de filtro estar presente.

Uma operação `Query` pode recuperar um máximo de 1 MB de dados. Esse limite se aplica antes de a expressão de filtro ser avaliada.

Uma expressão de filtro não pode conter atributos de chave de partição ou de chave de classificação. É necessário especificar esses atributos na expressão de condição principal, não na de filtro.

A sintaxe de uma expressão de filtro é semelhante à de uma expressão de condição de chave. As expressões de filtro podem usar os mesmos comparadores, funções e operadores lógicos que uma expressão de condição principal. Além disso, as expressões de filtro podem usar o operador diferente de (`<>`), bem como os operadores `OR`, `CONTAINS`, `IN`, `BEGINS_WITH`, `BETWEEN`, `EXISTS` e `SIZE`. Para obter mais informações, consulte [Principais expressões de condição para a operação de consulta no DynamoDB](Query.KeyConditionExpressions.md) e [Sintaxe para expressões de filtro e de condição](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.Syntax).

**Example**  
O exemplo da AWS CLI a seguir consulta a tabela `Thread` para encontrar um `ForumName` (chave de partição) e um `Subject` (chave de classificação) específicos. Dos itens que são encontrados, somente os threads de discussão mais populares são retornados – em outras palavras, apenas os threads com mais de um determinado número de `Views`.  

```
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
```
Os argumentos de `--expression-attribute-values` são armazenados no arquivo `values.json`.  

```
{
    ":fn":{"S":"Amazon DynamoDB"},
    ":sub":{"S":"DynamoDB Thread 1"},
    ":num":{"N":"3"}
}
```
Observe que `Views` é uma palavra reservada no DynamoDB (consulte [Palavras reservadas no DynamoDB](ReservedWords.md)), portanto, este exemplo usa `#v` como um espaço reservado. Para obter mais informações, consulte [Nomes (aliases) de atributo de expressão no DynamoDB](Expressions.ExpressionAttributeNames.md).

**nota**  
Uma expressão de filtro remove itens do conjunto de resultados de `Query`. Se possível, evite usar `Query` onde você espera recuperar um grande número de itens, mas também precisa descartar a maioria desses itens.

# Paginar os resultados de consultas à tabela no DynamoDB
<a name="Query.Pagination"></a>

O DynamoDB *pagina* os resultados das operações `Query`. Com a paginação, os resultados de `Query` são divididos em "páginas" de dados com 1 MB de tamanho (ou menos). Uma aplicação pode processar a primeira página de resultados e, em seguida, a segunda página, e assim por diante.

Uma única operação `Query` retorna apenas um conjunto de resultados que estão dentro do limite de tamanho de 1 MB. Para determinar se há mais resultados e para recuperá-los em uma página por vez, os aplicativos devem fazer o seguinte: 

1. Examine o resultado de `Query` de baixo nível:
   + Se o resultado contiver um elemento `LastEvaluatedKey` e ele não for nulo, prossiga para a etapa 2.
   + Se *não* houver um `LastEvaluatedKey` no resultado, não haverá mais itens a serem recuperados.

1. Crie uma `Query` com a mesma `KeyConditionExpression`. No entanto, desta vez, use o valor de `LastEvaluatedKey` da etapa 1 como o parâmetro `ExclusiveStartKey` na nova solicitação de `Query`.

1. Execute a nova solicitação de `Query`.

1. Vá para a etapa 1.

Em outras palavras, o valor `LastEvaluatedKey` de uma resposta de `Query` deve ser usado como `ExclusiveStartKey` da próxima solicitação de `Query`. Se não houver um elemento `LastEvaluatedKey` em uma resposta de `Query`, então, você recuperou a página de resultados final. Se `LastEvaluatedKey` não está vazio, isso não necessariamente significa que há mais dados no conjunto de resultados. A única maneira de saber quando você atingiu o final do conjunto de resultados é quando `LastEvaluatedKey` estiver vazio.

Você pode usar a AWS CLI para visualizar esse comportamento. A AWS CLI envia repetidamente solicitações `Query` de baixo nível ao DynamoDB até que `LastEvaluatedKey` não esteja mais presente nos resultados. Considere o seguinte exemplo da AWS CLI que recupera títulos de filmes de um determinado ano.

```
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
```

Normalmente, a AWS CLI lida com a paginação automaticamente. No entanto, neste exemplo, o parâmetro AWS CLI da `--page-size` limita o número de itens por página. O parâmetro de `--debug` imprime as informações de baixo nível sobre solicitações e respostas.

Se você executar o exemplo, a primeira resposta do DynamoDB será semelhante a esta.

```
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}'
```

O `LastEvaluatedKey` na resposta indica que nem todos os itens foram recuperados. A AWS CLI emite outra solicitação de `Query` para o DynamoDB. Essa solicitação e o padrão de resposta continuam, até a resposta final.

```
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}'
```

A ausência de `LastEvaluatedKey` indica que não há mais itens a serem recuperados.

**nota**  
Os AWS SDKs lidam com as respostas de baixo nível do DynamoDB (incluindo a presença ou a ausência de `LastEvaluatedKey`) e fornecem várias abstrações para paginar os resultados de `Query` Por exemplo, a interface do documento SDK para Java fornece o suporte a `java.util.Iterator` para que você possa abordar um resultado de cada vez.  
Para obter exemplos de código em várias linguagens de programação, consulte o [Guia de conceitos básicos do Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/) e a documentação do AWS SDK para sua linguagem.

Você também pode reduzir o tamanho da página limitando o número de itens no conjunto de resultados, com o parâmetro `Limit` da operação `Query`.

Para obter mais informações sobre como realizar consultas com o DynamoDB, veja [Consultar tabelas no DynamoDB](Query.md).

# Outros aspectos do trabalho com a operação de consulta no DynamoDB
<a name="Query.Other"></a>

Esta seção aborda aspectos adicionais da operação de consulta do DynamoDB, incluindo a limitação do tamanho dos resultados, a contagem de itens varridos versus retornados, o monitoramento do consumo da capacidade de leitura e o controle da consistência de leitura.

## Limitar o número de itens no conjunto de resultados
<a name="Query.Limit"></a>

Com a operação `Query`, você pode limitar o número de itens lidos. Para fazer isso, defina o parâmetro `Limit` com o número máximo de itens que você deseja.

Por exemplo, suponha que você execute a operação `Query` em uma tabela, com um valor de `Limit` igual a `6` e sem uma expressão de filtro. O resultado de `Query` contém os primeiros seis itens da tabela que correspondem à expressão de condição da chave da solicitação.

Agora suponha que você adicione uma expressão de filtro à operação `Query`. Nesse caso, o DynamoDB lê até seis itens e retorna somente aqueles que correspondem à expressão do filtro. O resultado final de `Query` contém seis itens ou menos, mesmo que mais itens tivessem correspondido à expressão do filtro se o DynamoDB continuasse lendo mais itens.

## Contar os itens nos resultados
<a name="Query.Count"></a>

Além dos itens que correspondem aos seus critérios, a resposta de `Query` contém os elementos a seguir:
+ `ScannedCount`: o número de itens que corresponderam à expressão de condição principal, *antes* que uma expressão de filtro (se alguma) fosse aplicada.
+ `Count`: o número de itens que permaneceram *depois* que uma expressão de filtro (se alguma) foi aplicada.

**nota**  
Se você não usar uma expressão de filtro, `ScannedCount` e `Count` terão o mesmo valor.

Se o tamanho do conjunto de resultados de `Query` for maior que 1 MB, `ScannedCount` e `Count` representarão apenas uma contagem parcial do total de itens. Você precisa executar várias operações `Query` para recuperar todos os resultados (consulte [Paginar os resultados de consultas à tabela no DynamoDB](Query.Pagination.md)).

Cada resposta de `Query` contém os valores de `ScannedCount` e de `Count` dos itens que foram processados pela solicitação de `Query` específica. Para obter os totais gerais de todas as solicitações de `Query`, você pode manter um total em execução de `ScannedCount` e `Count`.

## Unidades de capacidade consumidas por consulta
<a name="Query.CapacityUnits"></a>

Você pode usar `Query` em qualquer tabela ou índice secundário, desde que forneça o nome do atributo da chave de partição e um valor único para esse atributo. `Query` retorna todos os itens com esse valor de chave de partição. Opcionalmente, você pode fornecer um atributo de chave de classificação e usar um operador de comparação para refinar os resultados da pesquisa. `Query` As operações de API consomem unidades de capacidade de leitura da seguinte forma:


****  

| Se você executar uma operação `Query`... | O DynamoDB consumirá unidades de capacidade de leitura de... | 
| --- | --- | 
| Tabela | A capacidade de leitura provisionada da tabela. | 
| Índice secundário global | A capacidade de leitura provisionada do índice. | 
| Índice secundário local | A capacidade de leitura provisionada da tabela-base. | 

Por padrão, uma operação `Query` não retorna quaisquer dados sobre quanta capacidade de leitura ela consome. Entretanto, você pode especificar o parâmetro `ReturnConsumedCapacity` em uma solicitação de `Query` para obter essas informações. A seguir estão as configurações válidas de `ReturnConsumedCapacity`:
+ `NONE`: nenhum dado de capacidade consumida é retornado. (Esse é o padrão.)
+ `TOTAL`: a resposta inclui o número agregado de unidades de capacidade de leitura consumidas.
+ `INDEXES`: a resposta mostra o número agregado de unidades de capacidade de leitura consumidas, junto com a capacidade consumida para cada tabela e índice acessados.

O DynamoDB calcula o número de unidades de capacidade de leitura consumidas com base na quantidade e no tamanho desses itens, não na quantidade de dados exibidos para uma aplicação. Por esse motivo, o número de unidades de capacidade consumidas será o mesmo, independentemente de você solicitar todos os atributos (o comportamento padrão) ou apenas alguns deles (usando uma expressão de projeção). O número também é o mesmo, independentemente de você usar ou não uma expressão de filtro. `Query` consome uma unidade de capacidade mínima de leitura para realizar uma leitura altamente consistente por segundo ou duas leituras finais consistentes por segundo para um item de até 4 KB. Se você precisar ler um item com mais de 4 KB, o DynamoDB precisará de unidades de solicitação de leitura adicionais. Tabelas vazias e tabelas muito grandes que têm uma quantidade esparsa de chaves de partição podem ter algumas RCUs adicionais cobradas além da quantidade de dados consultados. Isso cobre o custo de atender à solicitação `Query`, mesmo que não existam dados.

## Consistência de leitura para consulta
<a name="Query.ReadConsistency"></a>

Uma operação `Query` executa leituras finais consistentes, por padrão. Isso significa que os resultados de `Query` talvez não reflitam as alterações causadas pelas operações `PutItem` ou `UpdateItem` concluídas recentemente. Para obter mais informações, consulte [Consistência de leitura do DynamoDB](HowItWorks.ReadConsistency.md).

Se você precisar de leituras fortemente consistentes, defina o parâmetro `ConsistentRead` como `true` na solicitação de `Query`.

# Verificar tabelas no DynamoDB
<a name="Scan"></a>

Uma operação `Scan` no Amazon DynamoDB lê cada item de uma tabela ou de um índice secundário. Por padrão, uma operação `Scan` retorna todos os atributos de dados de cada item na tabela ou índice. Você pode usar o parâmetro `ProjectionExpression` para que a operação `Scan` retorne apenas alguns dos atributos, em vez de todos eles.

`Scan` sempre retorna um conjunto de resultados. Se não forem encontrados itens correspondentes, o conjunto de resultados estará vazio.

Uma única solicitação de `Scan` pode recuperar um máximo de 1 MB de dados. Opcionalmente, o DynamoDB pode aplicar uma expressão de filtro a esses dados, restringindo os resultados antes que eles sejam retornados ao usuário.

**Topics**
+ [Expressões de filtro para verificação](#Scan.FilterExpression)
+ [Limitar o número de itens no conjunto de resultados](#Scan.Limit)
+ [Paginar resultados](#Scan.Pagination)
+ [Contar os itens nos resultados](#Scan.Count)
+ [Unidades de capacidade consumidas por verificação](#Scan.CapacityUnits)
+ [Consistência de leitura para verificação](#Scan.ReadConsistency)
+ [Verificar em paralelo](#Scan.ParallelScan)

## Expressões de filtro para verificação
<a name="Scan.FilterExpression"></a>

Se você precisar refinar ainda mais os resultados de `Scan`, existe a opção de utilizar uma expressão de filtro. Uma *expressão de filtro* determina quais itens dos resultados de `Scan` devem ser retornados para você. Todos os outros resultados serão descartados.

Uma expressão de filtro é aplicada depois que uma operação `Scan` é concluída, mas antes que os resultados sejam retornados. Portanto, uma operação `Scan` consome a mesma quantidade de capacidade de leitura, independentemente de uma expressão de filtro estar presente.

Uma operação `Scan` pode recuperar um máximo de 1 MB de dados. Esse limite se aplica antes de a expressão de filtro ser avaliada.

Com `Scan`, você pode especificar quaisquer atributos em uma expressão de filtro, incluindo atributos de chave de partição ou de chave de classificação.

A sintaxe de uma expressão de filtro é idêntica à de uma expressão de condição. As expressões de filtro podem usar os mesmos comparadores, funções e operadores lógicos que uma expressão de condição. Consulte [Expressões de condição e filtro, operadores e funções no DynamoDB](Expressions.OperatorsAndFunctions.md) para obter mais informações sobre operadores lógicos.

**Example**  
O exemplo da AWS Command Line Interface (AWS CLI) a seguir verifica a tabela `Thread` e retorna apenas os itens que foram publicados pela última vez por um usuário específico.  

```
aws dynamodb scan \
     --table-name Thread \
     --filter-expression "LastPostedBy = :name" \
     --expression-attribute-values '{":name":{"S":"User A"}}'
```

## Limitar o número de itens no conjunto de resultados
<a name="Scan.Limit"></a>

A operação `Scan` permite que você limite o número de itens retornados no resultado. Para fazer isso, defina o parâmetro `Limit` como o número máximo de itens que você deseja que a operação `Scan` retorne, antes da avaliação da expressão de filtro.

Por exemplo, suponha que você execute a operação `Scan` em uma tabela, com um valor de `Limit` igual a `6` e sem uma expressão de filtro. O resultado `Scan` contém os primeiros seis itens da tabela.

Agora suponha que você adicione uma expressão de filtro à operação `Scan`. Nesse caso, o DynamoDB aplicará a expressão de filtro aos seis itens que foram retornados e descarta os que não correspondem. O resultado final de `Scan` contém 6 itens ou menos, dependendo do número de itens que foram filtrados.

## Paginar resultados
<a name="Scan.Pagination"></a>

O DynamoDB *pagina* os resultados das operações `Scan`. Com a paginação, os resultados de `Scan` são divididos em "páginas" de dados com 1 MB de tamanho (ou menos). Uma aplicação pode processar a primeira página de resultados e, em seguida, a segunda página, e assim por diante.

Uma única operação `Scan` retorna apenas um conjunto de resultados que estão dentro do limite de tamanho de 1 MB. 

Para determinar se há mais resultados e para recuperá-los em uma página por vez, as aplicações devem fazer o seguinte:

1. Examine o resultado de `Scan` de baixo nível:
   + Se o resultado contiver um elemento `LastEvaluatedKey`, prossiga para a etapa 2.
   + Se *não* houver um `LastEvaluatedKey` no resultado, não haverá mais itens a serem recuperados.

1. Construa a nova solicitação de `Scan` com os mesmos parâmetros da anterior. No entanto, desta vez, use o valor de `LastEvaluatedKey` da etapa 1 como o parâmetro `ExclusiveStartKey` na nova solicitação de `Scan`.

1. Execute a nova solicitação de `Scan`.

1. Vá para a etapa 1.

Em outras palavras, o valor `LastEvaluatedKey` de uma resposta de `Scan` deve ser usado como `ExclusiveStartKey` da próxima solicitação de `Scan`. Se não houver um elemento `LastEvaluatedKey` em uma resposta de `Scan`, você terá recuperado a página de resultados final. (A ausência de `LastEvaluatedKey` é a única forma de você saber que chegou ao fim do conjunto de resultados.)

Você pode usar a AWS CLI para visualizar esse comportamento. A AWS CLI envia repetidamente solicitações `Scan` de baixo nível ao DynamoDB até que `LastEvaluatedKey` não esteja mais presente nos resultados. Considere o seguinte exemplo da AWS CLI que verifica toda a tabela `Movies`, mas retorna apenas os filmes de um determinado gênero.

```
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
```

Normalmente, a AWS CLI lida com a paginação automaticamente. No entanto, neste exemplo, o parâmetro AWS CLI da `--page-size` limita o número de itens por página. O parâmetro de `--debug` imprime as informações de baixo nível sobre solicitações e respostas.

**nota**  
Os resultados da paginação também serão diferentes com base nos parâmetros de entrada que você passar.   
O uso de `aws dynamodb scan --table-name Prices --max-items 1` retorna `NextToken`
O uso de `aws dynamodb scan --table-name Prices --limit 1` retorna `LastEvaluatedKey`.
Também esteja ciente de que usar`--starting-token`, em especial, requer o valor `NextToken`. 

Se você executar o exemplo, a primeira resposta do DynamoDB será semelhante ao seguinte:

```
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}'
```

O `LastEvaluatedKey` na resposta indica que nem todos os itens foram recuperados. A AWS CLI emite outra solicitação de `Scan` para o DynamoDB. Essa solicitação e o padrão de resposta continuam, até a resposta final.

```
2017-07-07 12:19:17,830 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":1,"Items":[{"title":{"S":"WarGames"}}],"ScannedCount":6}'
```

A ausência de `LastEvaluatedKey` indica que não há mais itens a serem recuperados.

**nota**  
Os AWS SDKs lidam com as respostas de baixo nível do DynamoDB (incluindo a presença ou a ausência de `LastEvaluatedKey`) e fornecem várias abstrações para paginar os resultados de `Scan` Por exemplo, a interface do documento SDK para Java fornece o suporte a `java.util.Iterator` para que você possa abordar um resultado de cada vez.  
Para obter exemplos de código em várias linguagens de programação, consulte o [Guia de conceitos básicos do Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/) e a documentação do AWS SDK para sua linguagem.

## Contar os itens nos resultados
<a name="Scan.Count"></a>

Além dos itens que correspondem aos seus critérios, a resposta de `Scan` contém os elementos a seguir:
+ `ScannedCount`: o número de itens avaliados antes de qualquer `ScanFilter` ser aplicado. Um valor alto de `ScannedCount` com poucos ou nenhum resultado de `Count` indica uma operação `Scan` ineficiente. Se você não tiver usado um filtro na solicitação, `ScannedCount` será o mesmo que `Count`. 
+ `Count`: o número de itens que permaneceram *depois* que uma expressão de filtro (se alguma) foi aplicada.

**nota**  
Se você não usar uma expressão de filtro, `ScannedCount` e `Count` terão o mesmo valor.

Se o tamanho do conjunto de resultados de `Scan` for maior que 1 MB, `ScannedCount` e `Count` representarão apenas uma contagem parcial do total de itens. Você precisa executar várias operações `Scan` para recuperar todos os resultados (consulte [Paginar resultados](#Scan.Pagination)).

Cada resposta de `Scan` contém os valores de `ScannedCount` e de `Count` dos itens que foram processados pela solicitação de `Scan` específica. Para obter os totais gerais de todas as solicitações de `Scan`, você pode manter um total em execução de `ScannedCount` e de `Count`.

## Unidades de capacidade consumidas por verificação
<a name="Scan.CapacityUnits"></a>

Você pode executar `Scan` em qualquer tabela ou índice secundário. As operações `Scan` consomem unidades de capacidade de leitura da seguinte forma.


****  

| Se você executar uma operação `Scan`... | O DynamoDB consumirá unidades de capacidade de leitura de... | 
| --- | --- | 
| Tabela | A capacidade de leitura provisionada da tabela. | 
| Índice secundário global | A capacidade de leitura provisionada do índice. | 
| Índice secundário local | A capacidade de leitura provisionada da tabela-base. | 

**nota**  
Atualmente, o acesso entre contas para operações de verificação de índice secundário não é aceito em [políticas baseadas em recursos](access-control-resource-based.md).

Por padrão, uma operação `Scan` não retorna quaisquer dados sobre quanta capacidade de leitura ela consome. Entretanto, você pode especificar o parâmetro `ReturnConsumedCapacity` em uma solicitação de `Scan` para obter essas informações. A seguir estão as configurações válidas de `ReturnConsumedCapacity`:
+ `NONE`: nenhum dado de capacidade consumida é retornado. (Esse é o padrão.)
+ `TOTAL`: a resposta inclui o número agregado de unidades de capacidade de leitura consumidas.
+ `INDEXES`: a resposta mostra o número agregado de unidades de capacidade de leitura consumidas, junto com a capacidade consumida para cada tabela e índice acessados.

O DynamoDB calcula o número de unidades de capacidade de leitura consumidas com base na quantidade e no tamanho desses itens, não na quantidade de dados exibidos para uma aplicação. Por esse motivo, o número de unidades de capacidade consumidas será o mesmo, independentemente de você solicitar todos os atributos (o comportamento padrão) ou apenas alguns deles (usando uma expressão de projeção). O número também é o mesmo, independentemente de você usar ou não uma expressão de filtro. `Scan` consome uma unidade de capacidade mínima de leitura para realizar uma leitura altamente consistente por segundo ou duas leituras finais consistentes por segundo para um item de até 4 KB. Se você precisar ler um item com mais de 4 KB, o DynamoDB precisará de unidades de solicitação de leitura adicionais. Tabelas vazias e tabelas muito grandes que têm uma quantidade esparsa de chaves de partição podem ter algumas RCUs adicionais cobradas além da quantidade de dados verificados. Isso cobre o custo de atender à solicitação `Scan`, mesmo que não existam dados.

## Consistência de leitura para verificação
<a name="Scan.ReadConsistency"></a>

Uma operação `Scan` executa leituras finais consistentes, por padrão. Isso significa que os resultados de `Scan` talvez não reflitam as alterações causadas pelas operações `PutItem` ou `UpdateItem` concluídas recentemente. Para obter mais informações, consulte [Consistência de leitura do DynamoDB](HowItWorks.ReadConsistency.md).

Se você precisar de leituras altamente consistentes, como a hora em que a operação `Scan` começa, defina o parâmetro `ConsistentRead` como `true` na solicitação de `Scan`. Isso garante que todas as operações de gravação que foram concluídas antes de `Scan` ter começado sejam incluídas na resposta de `Scan`. 

Pode ser útil configurar `ConsistentRead` como `true` no backup da tabela ou em cenários de replicação, juntamente com o [Amazon DynamoDB Streams](./Streams.html). Primeiro, você usa `Scan` com `ConsistentRead` definida como true para obter uma cópia consistente dos dados na tabela. Durante a operação `Scan`, o DynamoDB Streams registra qualquer atividade de gravação adicional que ocorra na tabela. Após a conclusão de `Scan`, você pode aplicar a atividade de gravação do fluxo à tabela.

**nota**  
Uma operação `Scan` com `ConsistentRead` definida como `true` consome duas vezes mais unidades de capacidade de leitura, em comparação com deixar `ConsistentRead` com seu valor padrão (`false`).

## Verificar em paralelo
<a name="Scan.ParallelScan"></a>

Por padrão, a operação `Scan` processa os dados sequencialmente. O Amazon DynamoDB retorna os dados para a aplicação em incrementos de 1 MB, e uma aplicação realiza operações `Scan` adicionais para recuperar os próximos 1 MB de dados. 

Quanto maior a tabela ou índice que está sendo verificado, mais tempo a operação `Scan` levará para ser concluída. Além disso, uma operação `Scan` sequencial talvez nem sempre consiga utilizar totalmente a capacidade de throughput de leitura provisionada: embora o DynamoDB distribua os dados de uma tabela grande entre várias partições físicas, uma operação `Scan` pode ler apenas uma partição de cada vez. Por esse motivo, o throughput de uma operação `Scan` é restrita pelo throughput máximo de uma única partição.

Para solucionar esses problemas, a operação `Scan` pode dividir logicamente uma tabela ou um índice secundário em vários *segmentos*, com vários operadores da aplicação verificando os segmentos em paralelo. Cada operador pode ser um thread (em linguagens de programação que aceitam multithreading) ou um processo do sistema operacional. Para executar uma verificação em paralelo, cada operador emite sua própria solicitação de `Scan` com os seguintes parâmetros:
+ `Segment`: um segmento a ser verificado por um determinado operador. Cada operador deve usar um valor diferente para `Segment`.
+ `TotalSegments`: o número total de segmentos para a verificação em paralelo. Esse valor deve ser o mesmo que o número de operadores que sua aplicação usará.

O diagrama a seguir mostra como uma aplicação multithread executa uma operação `Scan` em paralelo com três níveis de paralelismo:

![\[Uma aplicação multithread que executa uma verificação paralela, dividindo uma tabela em três segmentos.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/ParallelScan.png)




Neste diagrama, a aplicação gera três threads e atribui um número a cada thread. (Segmentos são baseados em zero, portanto, o primeiro número é sempre 0.) Cada thread emite uma solicitação de `Scan`, configurando `Segment` como seu número designado e `TotalSegments` como 3. Cada thread verifica seu segmento designado, recuperando 1 MB de dados por vez, e retorna os dados para o thread principal da aplicação.

O DynamoDB atribui itens a *segmentos* aplicando uma função hash à chave de partição de cada item. Para determinado valor `TotalSegments`, todos os itens com a mesma chave de partição são sempre atribuídos ao mesmo `Segment`. Isso significa que, em uma tabela em que o *Item 1*, o *Item 2* e o *Item 3* compartilham `pk="account#123"` (mas têm chaves de classificação diferentes), esses itens serão processados pelo mesmo trabalhador, independentemente dos valores da chave de classificação ou do tamanho da *coleção de itens*.

Como a atribuição de *segmentos* é baseada somente no hash da chave de partição, os segmentos podem ser distribuídos de forma desigual. Alguns segmentos podem não conter itens, enquanto outros podem conter muitas chaves de partição com grandes coleções de itens. Como resultado, aumentar o número total de segmentos não garante uma performance mais rápida de verificação, especialmente quando as chaves de partição não são distribuídas de modo uniforme no espaço de teclas.

Os valores para `Segment` e `TotalSegments` aplicam-se a solicitações de `Scan` individuais, e você pode usar valores diferentes a qualquer momento. Talvez você precise experimentar com esses valores, e o número de operadores que usa, até que seu aplicativo atinja a melhor performance.

**nota**  
Uma operação Scan em paralelo com um grande número de operadores pode facilmente consumir todo o throughput provisionado da tabela ou índice que está sendo verificado. É melhor evitar tais verificações, se a tabela ou índice também incorrer em uso intensivo de atividades de leitura ou de gravação de outras aplicações.  
Para controlar a quantidade de dados retornados por solicitação, use o parâmetro `Limit`. Isso pode ajudar a evitar situações em que um operador consome todo o throughput provisionado, às custas de todos os outros operadores.

# PartiQL: uma linguagem de consultas compatível com SQL para o Amazon DynamoDB
<a name="ql-reference"></a>

O Amazon DynamoDB oferece suporte a [PartiQL](https://partiql.org/), uma linguagem de consultas compatível com SQL, para selecionar, inserir, atualizar e excluir dados no Amazon DynamoDB. Usando PartiQL, você pode interagir facilmente com tabelas do DynamoDB e executar consultas ad hoc usando o Console de gerenciamento da AWS, o NoSQL Workbench, a AWS Command Line Interfacee as APIs do DynamoDB para PartiQL.

As operações PartiQL fornecem as mesmas disponibilidade, latência e performance que as outras operações de plano de dados do DynamoDB.

As seções a seguir descrevem a implementação de PartiQL do DynamoDB.

**Topics**
+ [O que é PartiQL?](#ql-reference.what-is)
+ [PartiQL no Amazon DynamoDB](#ql-reference.what-is)
+ [Introdução](ql-gettingstarted.md)
+ [Tipos de dados](ql-reference.data-types.md)
+ [Declarações](ql-reference.statements.md)
+ [Funções](ql-functions.md)
+ [Operadores](ql-operators.md)
+ [Transações](ql-reference.multiplestatements.transactions.md)
+ [Operações em lote](ql-reference.multiplestatements.batching.md)
+ [Políticas do IAM](ql-iam.md)

## O que é PartiQL?
<a name="ql-reference.what-is"></a>

A linguagem *PartiQL* garante acesso de consultas compatíveis com SQL em vários armazenamentos de dados que contêm dados estruturados, dados semiestruturados e dados aninhados. Ela é amplamente utilizada na Amazon e agora está disponível como parte de muitos serviços da AWS, incluindo o DynamoDB.

Para obter a especificação da PartiQL e um tutorial sobre a linguagem de consulta principal, consulte a [Documentação da PartiQL](https://partiql.org/docs.html).

**nota**  
O Amazon DynamoDB oferece suporte a um *subconjunto* da linguagem de consultas [PartiQL](https://partiql.org/).
O Amazon DynamoDB não é compatível com o formato de dados [Amazon Ion](http://amzn.github.io/ion-docs/) nem com liderais do Amazon Ion.

## PartiQL no Amazon DynamoDB
<a name="ql-reference.what-is"></a>

Para executar consultas PartiQL no DynamoDB, você pode usar:
+ O console do DynamoDB
+ O NoSQL Workbench
+ A AWS Command Line Interface (AWS CLI)
+ As APIs do DynamoDB

Para obter informações sobre como usar esses métodos para acessar o DynamoDB, consulte [Acesso ao DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AccessingDynamoDB.html).

# Conceitos básicos de PartiQL para DynamoDB
<a name="ql-gettingstarted"></a>

Esta seção descreve como usar PartiQL para DynamoDB via console do Amazon DynamoDB, AWS Command Line Interface (AWS CLI) e APIs do DynamoDB.

Nos exemplos a seguir, a tabela do DynamoDB definida no tutorial [Conceitos básicos do DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStartedDynamoDB.html) é um pré-requisito.

Para obter informações sobre como usar o console do DynamoDB, a AWS Command Line Interface ou as APIs do DynamoDB para acessar o DynamoDB, consulte [Acesso ao DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AccessingDynamoDB.html).

Para [baixar](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html) e usar o [NoSQL Workbench](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.html) para criar instruções em [PartiQL para DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html), escolha **PartiQL Operations** (Operações PartiQL) no canto superior direito do [Criador de operações](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.querybuilder.operationbuilder.html) do NoSQL Workbench para DynamoDB.

------
#### [ Console ]

![\[Interface do Editor PartiQL que mostra o resultado da execução da operação de consulta na tabela Music.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/partiqlgettingstarted.png)


1. Faça login no Console de gerenciamento da AWS e abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/).

1. No painel de navegação, no lado esquerdo do console, selecione **PartiQL editor** (Editor de PartiQL).

1. Escolha a tabela **Music**.

1. Escolha **Query table** (Consultar tabela). Essa ação gera uma consulta que não resultará em uma varredura de tabela completa.

1. Substitua `partitionKeyValue` pelo valor da string `Acme Band`. Substitua `sortKeyValue` pelo valor da string `Happy Day`.

1. Selecione o botão **Run (Executar)**. 

1. Você pode visualizar os resultados da consulta escolhendo a opção **Table view** (Visualização da tabela ou **JSON view** (Visualização de JSON). 

------
#### [ NoSQL workbench ]

![\[Interface do NoSQL Workbench. Ela mostra uma declaração PartiQL SELECT que você pode executar na tabela Music.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/workbench/partiql.single.png)


1. Escolha **PartiQL statement** (Instrução PartiQL).

1. Insira a seguinte [instrução SELECT](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html) PartiQL 

   ```
   SELECT *                                         
   FROM Music  
   WHERE Artist=? and SongTitle=?
   ```

1. Para especificar um valor para os parâmetros `Artist` e `SongTitle`:

   1. Escolha **Optional request parameters** (Parâmetros de solicitação opcionais).

   1. Escolha **Add new parameters** (Adicionar novos parâmetros).

   1. Escolha o tipo de atributo **string** e o valor `Acme Band`.

   1. Repita as etapas b e c e escolha o tipo **string** e o valor `PartiQL Rocks`. 

1. Se desejar gerar código, escolha **Generate code** (Gerar código).

   Selecione a linguagem desejada nas guias exibidas. Agora você pode copiar esse código e usá-lo na sua aplicação.

1. Se desejar que a operação seja executada imediatamente, escolha **Run** (Executar).

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

1. Crie um item na tabela `Music` usando a instrução PartiQL INSERT. 

   ```
   aws dynamodb execute-statement --statement "INSERT INTO Music  \
   					    VALUE  \
   					    {'Artist':'Acme Band','SongTitle':'PartiQL Rocks'}"
   ```

1. Recupere um item da tabela Music usando a instrução PartiQL SELECT.

   ```
   aws dynamodb execute-statement --statement "SELECT * FROM Music   \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

1. Atualize um item na tabela `Music` usando a instrução 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'"
   ```

   Adicione um valor de lista para um item na tabela `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Remova um valor de lista para um item na tabela `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               REMOVE AwardDetail.Grammys[2]  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Adicione um novo membro de mapa para um item na tabela `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardDetail.BillBoard=[2020]  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Adicione um novo atributo de conjunto de strings para um item na tabela `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET BandMembers =<<'member1', 'member2'>>  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Atualize um atributo de conjunto de strings para um item na tabela `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET BandMembers =set_add(BandMembers, <<'newmember'>>)  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

1. Exclua um item da tabela `Music` usando a instrução 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());
        }
    }

}
```

------

## Usar instruções parametrizadas
<a name="ql-gettingstarted.parameterized"></a>

Em vez de incorporar valores diretamente em uma string de instrução PartiQL, é possível usar espaços reservados com ponto de interrogação (`?`) e fornecer os valores separadamente no campo `Parameters`. Cada `?` é substituído pelo valor do parâmetro correspondente, na ordem em que é fornecido.

Usar instruções parametrizadas é uma prática recomendada porque separa a estrutura da instrução dos valores dos dados, facilitando a leitura e a reutilização das instruções. Isso também evita a necessidade de formatar e escapar manualmente dos valores dos atributos na string da instrução.

É possível usar instruções parametrizadas nas operações `ExecuteStatement`, `BatchExecuteStatement` e `ExecuteTransaction`.

Os exemplos a seguir recuperam um item da tabela `Music` usando valores parametrizados para a chave de partição e a chave de classificação.

------
#### [ 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'}
    ]
)
```

------

**nota**  
O exemplo Java na seção de introdução anterior sempre usa instruções parametrizadas. O método `getPartiQLParameters()` cria a lista de parâmetros e cada instrução usa `?` como espaço reservado em vez de valores em linha.

# Tipos de dados de PartiQL para DynamoDB
<a name="ql-reference.data-types"></a>

A tabela a seguir lista os tipos de dados que você pode usar com a linguagem PartiQL para DynamoDB.

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/ql-reference.data-types.html)

## Exemplos
<a name="ql-reference.data-types"></a>

A instrução a seguir demonstra como inserir os seguintes tipos de dados: `String`, `Number`, `Map`, `List`, `Number Set` e `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'>>
}
```

A instrução a seguir demonstra como inserir novos elementos nos tipos `Map`, `List`, `Number Set` e `String Set` e alterar o valor de um tipo `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'
```

A instrução a seguir demonstra como remover elementos dos tipos `Map`, `List`, `Number Set` e `String Set` e alterar o valor de um tipo `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'
```

Para obter mais informações, consulte [Tipos de dados do DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes).

# Instruções em PartiQL para DynamoDB
<a name="ql-reference.statements"></a>

O Amazon DynamoDB oferece suporte às instruções PartiQL a seguir.

**nota**  
O DynamoDB não oferece suporte a todas as instruções PartiQL.  
Esta referência apresenta a sintaxe básica e fornece exemplos de uso de instruções PartiQL que você deve executar manualmente usando o AWS CLI ou APIs.

*Linguagem de manipulação de dados* (DML) é o conjunto de instruções PartiQL que você usa para gerenciar dados em tabelas do DynamoDB. Você usa instruções DML para adicionar, modificar ou excluir dados em uma tabela.

As seguintes instruções de linguagem DML e consultas são aceitas:
+ [Instruções Select em PartiQL para DynamoDB](ql-reference.select.md)
+ [Instruções Update em PartiQL para DynamoDB](ql-reference.update.md)
+ [Instruções Insert em PartiQL para DynamoDB](ql-reference.insert.md)
+ [Instruções Delete em PartiQL para DynamoDB](ql-reference.delete.md)

[Executar transações com PartiQL para DynamoDB](ql-reference.multiplestatements.transactions.md) e [Executar operações em lote com PartiQL para DynamoDB](ql-reference.multiplestatements.batching.md) também são compatíveis com a linguagem PartiQL para DynamoDB.

# Instruções Select em PartiQL para DynamoDB
<a name="ql-reference.select"></a>

Use a instrução `SELECT` para recuperar dados de uma tabela no Amazon DynamoDB.

O uso da declaração `SELECT` poderá gerar uma verificação completa da tabela se uma condição de igualdade ou IN com uma chave de partição não for fornecida na cláusula WHERE. Uma operação de verificação examina todos os itens com os valores solicitados e pode usar o throughput provisionado para uma tabela ou índice grande em uma única operação. 

Se desejar evitar a verificação completa da tabela em PartiQL, você pode:
+ Criar suas instruções `SELECT` para não resultar em verificações completas de tabela, certificando-se de que a [condição da cláusula WHERE](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html#ql-reference.select.parameters) seja configurada de acordo.
+ Desativar verificações completas de tabela usando a política do IAM especificada em [Exemplo: permitir instruções Select e negar instruções de verificação de tabela completa em PartiQL para DynamoDB](ql-iam.md#access-policy-ql-iam-example6), conforme descrito no Guia do desenvolvedor do DynamoDB.

Para obter mais informações, consulte [Melhores práticas para consulta e verificação de dados](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-query-scan.html) no Guia do desenvolvedor do DynamoDB.

**Topics**
+ [Sintaxe](#ql-reference.select.syntax)
+ [Parâmetros](#ql-reference.select.parameters)
+ [Exemplos](#ql-reference.select.examples)

## Sintaxe
<a name="ql-reference.select.syntax"></a>

```
SELECT expression  [, ...] 
FROM table[.index]
[ WHERE condition ] [ [ORDER BY key [DESC|ASC] , ...]
```

## Parâmetros
<a name="ql-reference.select.parameters"></a>

***expressão***  
(Obrigatório) Uma projeção formada a partir do curinga `*` ou uma lista de projeção de um ou mais nomes de atributos ou caminhos de documentos do conjunto de resultados. Uma expressão pode consistir em chamadas para [Usar funções PartiQL com o DynamoDB](ql-functions.md) ou campos que são modificados por [Operadores aritméticos, comparativos e lógicos de PartiQL para DynamoDB](ql-operators.md).

***table***  
(Obrigatório) O nome da tabela a ser consultada.

***Índice do***  
(Opcional) O nome do índice para consultar.  
É necessário adicionar aspas duplas ao nome da tabela e ao nome do índice ao consultar um índice.  

```
SELECT * 
FROM "TableName"."IndexName"
```

***Condição***  
(Opcional) Os critérios de seleção para a consulta.  
Para garantir que uma instrução `SELECT` não resulte em uma verificação completa da tabela, a condição da cláusula `WHERE` deverá especificar uma chave de partição. Use o operador de igualdade ou IN.  
Por exemplo, se você tiver uma tabela `Orders` com uma partição `OrderID` e outros atributos não chave, incluindo um `Address`, as seguintes instruções não resultarão em uma varredura completa da tabela:  

```
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]
```
As instruções `SELECT` a seguir, no entanto, resultarão em uma varredura completa da tabela:  

```
SELECT * 
FROM "Orders" 
WHERE OrderID > 1

SELECT * 
FROM "Orders" 
WHERE Address='some address'

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 OR Address='some address'
```

***key***  
(Opcional) Uma chave de hash ou uma chave de classificação a ser usada para ordenar os resultados retornados. A ordem padrão é crescente (`ASC`). Especifique `DESC` se desejar que os resultados sejam retornados em ordem decrescente.

**nota**  
Se você omitir a cláusula `WHERE`, todos os itens da tabela serão recuperados.

## Exemplos
<a name="ql-reference.select.examples"></a>

A consulta a seguir retorna um item, se houver, da tabela `Orders` mediante a especificação da chave de partição `OrderID` e o uso do operador de igualdade.

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID = 1
```

A consulta a seguir retorna todos os itens na tabela `Orders` que têm uma chave de partição específica, `OrderID`, valores usando o operador OR.

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID = 1 OR OrderID = 2
```

A consulta a seguir retorna todos os itens na tabela `Orders` que têm uma chave de partição específica, `OrderID`, valores usando o operador IN. Os resultados retornados estão em ordem decrescente, com base no valor de atributo de chave `OrderID`.

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID IN [1, 2, 3] ORDER BY OrderID DESC
```

A consulta a seguir mostra uma varredura de tabela completa que retorna todos os itens da tabela `Orders`que têm uma `Total` maior que 500, onde `Total` é um atributo não chave.

```
SELECT OrderID, Total 
FROM "Orders"
WHERE Total > 500
```

A consulta a seguir mostra uma varredura de tabela completa que retorna todos os itens da tabela `Orders` em um intervalo de ordem `Total` específico, usando o operador IN e um atributo não chave `Total`.

```
SELECT OrderID, Total 
FROM "Orders"
WHERE Total IN [500, 600]
```

A consulta a seguir mostra uma varredura de tabela completa que retorna todos os itens da tabela `Orders` em um intervalo de ordem `Total` específico, usando o operador BETWEEN e um atributo não chave `Total`.

```
SELECT OrderID, Total 
FROM "Orders" 
WHERE Total BETWEEN 500 AND 600
```

A consulta a seguir retorna a primeira data em que um dispositivo firestick foi usado para observar mediante a especificação da chave de partição `CustomerID` e da chave de classificação `MovieID` na condição da cláusula WHERE e usando caminhos de documento na cláusula SELECT.

```
SELECT Devices.FireStick.DateWatched[0] 
FROM WatchList 
WHERE CustomerID= 'C1' AND MovieID= 'M1'
```

A consulta a seguir mostra uma verificação de tabela completa que retorna a lista de itens em que um dispositivo firestick foi usado pela primeira vez após 24/12/19 usando caminhos de documento na condição da cláusula WHERE.

```
SELECT Devices 
FROM WatchList 
WHERE Devices.FireStick.DateWatched[0] >= '12/24/19'
```

# Instruções Update em PartiQL para DynamoDB
<a name="ql-reference.update"></a>

Use a instrução `UPDATE` para modificar o valor de um ou mais atributos em um item em uma tabela do Amazon DynamoDB. 

**nota**  
Você só pode atualizar um item de cada vez; não é possível emitir uma única instrução PartiQL do DynamoDB para atualizar vários itens. Para obter informações sobre como atualizar vários itens, consulte [Executar transações com PartiQL para DynamoDB](ql-reference.multiplestatements.transactions.md) ou [Executar operações em lote com PartiQL para DynamoDB](ql-reference.multiplestatements.batching.md).

**Topics**
+ [Sintaxe](#ql-reference.update.syntax)
+ [Parâmetros](#ql-reference.update.parameters)
+ [Valor de retorno](#ql-reference.update.return)
+ [Exemplos](#ql-reference.update.examples)

## Sintaxe
<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] *
```

## Parâmetros
<a name="ql-reference.update.parameters"></a>

***table***  
(Obrigatório) A tabela que contém os dados a serem modificados.

***caminho***  
(Obrigatório) Um nome de atributo ou caminho de documento a ser criado ou modificado.

***data***  
(Obrigatório) Um valor de atributo ou o resultado de uma operação.  
As operações com suporte a serem usadas com SET:  
+ LIST\$1APPEND: adiciona um valor a um tipo de lista.
+ SET\$1ADD: adiciona um valor a um conjunto de números ou strings.
+ SET\$1DELETE: remove um valor de um conjunto de números ou strings.

***Condição***  
(Obrigatório) Os critérios de seleção para o item a ser modificado. Essa condição deve ser resolvida em um único valor de chave primária.

***returnvalues***  
(Opcional) Use `returnvalues` se desejar obter os atributos de item como eles aparecem antes ou depois de serem atualizados. Os valores válidos são:   
+ `ALL OLD *`: retorna todos os atributos do item como eles apareciam antes da operação de atualização.
+ `MODIFIED OLD *`: retorna somente os atributos atualizados como eles apareciam antes da operação de atualização.
+ `ALL NEW *`: retorna todos os atributos do item como eles aparecem após a operação de atualização.
+ `MODIFIED NEW *` : retorna somente os atributos atualizados como eles aparecem após a operação `UpdateItem`.

## Valor de retorno
<a name="ql-reference.update.return"></a>

Esta instrução não retornará um valor a menos que o parâmetro `returnvalues` seja especificado.

**nota**  
Se a cláusula WHERE da instrução UPDATE não for avaliada como true para nenhum item na tabela do DynamoDB, `ConditionalCheckFailedException` será retornado.

## Exemplos
<a name="ql-reference.update.examples"></a>

Atualiza um valor de atributo em um item existente. Se o atributo não existir, ele será criado.

A consulta a seguir atualiza um item na tabela `"Music"` adicionando um atributo do tipo Number (`AwardsWon`) e um atributo do tipo Map (`AwardDetail`).

```
UPDATE "Music" 
SET AwardsWon=1 
SET AwardDetail={'Grammys':[2020, 2018]}  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

Você pode adicionar `RETURNING ALL OLD *` para retornar os atributos como eles apareceram antes da operação `Update`.

```
UPDATE "Music" 
SET AwardsWon=1 
SET AwardDetail={'Grammys':[2020, 2018]}  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
RETURNING ALL OLD *
```

Isso retorna o seguinte:

```
{
    "Items": [
        {
            "Artist": {
                "S": "Acme Band"
            },
            "SongTitle": {
                "S": "PartiQL Rocks"
            }
        }
    ]
}
```

Você pode adicionar `RETURNING ALL NEW *` para retornar os atributos como eles apareceram depois da operação `Update`.

```
UPDATE "Music" 
SET AwardsWon=1 
SET AwardDetail={'Grammys':[2020, 2018]}  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
RETURNING ALL NEW *
```

Isso retorna o seguinte:

```
{
    "Items": [
        {
            "AwardDetail": {
                "M": {
                    "Grammys": {
                        "L": [
                            {
                                "N": "2020"
                            },
                            {
                                "N": "2018"
                            }
                        ]
                    }
                }
            },
            "AwardsWon": {
                "N": "1"
            }
        }
    ]
}
```

A consulta a seguir atualiza um item na tabela `"Music"` anexando-o a uma lista `AwardDetail.Grammys`.

```
UPDATE "Music" 
SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

A consulta a seguir atualiza um item na tabela `"Music"` removendo-o de uma lista `AwardDetail.Grammys`.

```
UPDATE "Music" 
REMOVE AwardDetail.Grammys[2]   
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

A consulta a seguir atualiza um item na tabela `"Music"` adicionando `BillBoard` ao mapa `AwardDetail`.

```
UPDATE "Music" 
SET AwardDetail.BillBoard=[2020] 
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

A consulta a seguir atualiza um item na tabela `"Music"` adicionando o atributo de conjunto de strings `BandMembers`.

```
UPDATE "Music" 
SET BandMembers =<<'member1', 'member2'>> 
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

A consulta a seguir atualiza um item na tabela `"Music"` adicionando `newbandmember` ao conjunto de strings `BandMembers`.

```
UPDATE "Music" 
SET BandMembers =set_add(BandMembers, <<'newbandmember'>>) 
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

# Instruções Delete em PartiQL para DynamoDB
<a name="ql-reference.delete"></a>

Use a instrução `DELETE` para excluir um item existente da tabela do Amazon DynamoDB.

**nota**  
É possível excluir apenas um item de cada vez. Você não pode emitir uma única instrução PartiQL do DynamoDB para excluir vários itens. Para obter informações sobre como excluir vários itens, consulte [Executar transações com PartiQL para DynamoDB](ql-reference.multiplestatements.transactions.md) ou [Executar operações em lote com PartiQL para DynamoDB](ql-reference.multiplestatements.batching.md).

**Topics**
+ [Sintaxe](#ql-reference.delete.syntax)
+ [Parâmetros](#ql-reference.delete.parameters)
+ [Valor de retorno](#ql-reference.delete.return)
+ [Exemplos](#ql-reference.delete.examples)

## Sintaxe
<a name="ql-reference.delete.syntax"></a>

```
DELETE FROM table 
 WHERE condition [RETURNING returnvalues]
 <returnvalues>  ::= ALL OLD *
```

## Parâmetros
<a name="ql-reference.delete.parameters"></a>

***table***  
(Obrigatório) A tabela do DynamoDB que contém o item a ser excluído.

***Condição***  
(Obrigatório) Os critérios de seleção para o item a ser excluído; essa condição deve ser resolvida para um único valor de chave primária.

***returnvalues***  
(Opcional) Use `returnvalues` se desejar obter os atributos do item como eles apareciam antes de ser excluídos. Os valores válidos são:   
+ `ALL OLD *`: o conteúdo do item antigo é retornado.

## Valor de retorno
<a name="ql-reference.delete.return"></a>

Esta instrução não retornará um valor a menos que o parâmetro `returnvalues` seja especificado.

**nota**  
Se a tabela do DynamoDB não tiver nenhum item com a mesma chave primária que a do item para o qual a instrução DELETE foi emitida, SUCESS será retornado com 0 itens excluídos. Se a tabela tiver um item com a mesma chave primária, mas a condição na cláusula WHERE da instrução DELETE for avaliada como false, `ConditionalCheckFailedException` será retornado.

## Exemplos
<a name="ql-reference.delete.examples"></a>

A consulta a seguir exclui um item da tabela `"Music"`.

```
DELETE FROM "Music" WHERE "Artist" = 'Acme Band' AND "SongTitle" = 'PartiQL Rocks'
```

Você pode adicionar o parâmetro `RETURNING ALL OLD *` para retornar os dados que foram excluídos.

```
DELETE FROM "Music" WHERE "Artist" = 'Acme Band' AND "SongTitle" = 'PartiQL Rocks' RETURNING ALL OLD *
```

A instrução `Delete` agora retorna o seguinte:

```
{
    "Items": [
        {
            "Artist": {
                "S": "Acme Band"
            },
            "SongTitle": {
                "S": "PartiQL Rocks"
            }
        }
    ]
}
```

# Instruções Insert em PartiQL para DynamoDB
<a name="ql-reference.insert"></a>

Use a instrução `INSERT` para adicionar um item a uma tabela no Amazon DynamoDB.

**nota**  
Você só pode inserir um item de cada vez; não é possível emitir uma única instrução PartiQL do DynamoDB para inserir vários itens. Para obter informações sobre como inserir vários itens, consulte [Executar transações com PartiQL para DynamoDB](ql-reference.multiplestatements.transactions.md) ou [Executar operações em lote com PartiQL para DynamoDB](ql-reference.multiplestatements.batching.md).

**Topics**
+ [Sintaxe](#ql-reference.insert.syntax)
+ [Parâmetros](#ql-reference.insert.parameters)
+ [Valor de retorno](#ql-reference.insert.return)
+ [Exemplos](#ql-reference.insert.examples)

## Sintaxe
<a name="ql-reference.insert.syntax"></a>

Insira um único item.

```
INSERT INTO table VALUE item
```

## Parâmetros
<a name="ql-reference.insert.parameters"></a>

***table***  
(Obrigatório) A tabela na qual você deseja inserir os dados. A tabela já deve existir.

***item***  
(Obrigatório) Um item válido do DynamoDB representado como uma [tupla PartiQL](https://partiql.org/docs.html). Você só deve especificar *um* item, e cada nome de atributo no item diferencia maiúsculas e minúsculas e pode ser indicado com aspas *simples* (`'...'`) na linguagem PartiQL.  
Os valores de string também são denotados com aspas *simples* (`'...'`) em PartiQL.

## Valor de retorno
<a name="ql-reference.insert.return"></a>

Esta instrução não retorna nenhum valor.

**nota**  
Se a tabela do DynamoDB já tiver um item com a mesma chave primária da chave primária do item que está sendo inserido, `DuplicateItemException` será retornado.

## Exemplos
<a name="ql-reference.insert.examples"></a>

```
INSERT INTO "Music" value {'Artist' : 'Acme Band','SongTitle' : 'PartiQL Rocks'}
```

# Usar funções PartiQL com o DynamoDB
<a name="ql-functions"></a>

A linguagem PartiQL no Amazon DynamoDB é compatível com as seguintes variantes integradas de funções padrão SQL.

**nota**  
As funções SQL que não fazem parte desta lista não são aceitas no DynamoDB.

## Funções agregadas
<a name="ql-functions.aggregate"></a>
+ [Usar a função SIZE com PartiQL para Amazon DynamoDB](ql-functions.size.md)

## Funções condicionais
<a name="ql-functions.conditional"></a>
+ [Usar a função EXISTS com PartiQL para DynamoDB](ql-functions.exists.md)
+ [Usar a função ATTRIBUTE\$1TYPE com PartiQL para DynamoDB](ql-functions.attribute_type.md)
+ [Usar a função BEGINS\$1WITH com PartiQL para DynamoDB](ql-functions.beginswith.md)
+ [Usar a função CONTAINS com PartiQL para DynamoDB](ql-functions.contains.md)
+ [Usar a função MISSING com PartiQL para DynamoDB](ql-functions.missing.md)

# Usar a função EXISTS com PartiQL para DynamoDB
<a name="ql-functions.exists"></a>

Você pode usar EXISTS para executar a mesma função que `ConditionCheck` na API [TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems). A função EXISTS só pode ser usada em transações.

Sendo fornecido um valor, a função retornará `TRUE` se o valor for uma coleção não vazia. Caso contrário, gera `FALSE`.

**nota**  
Essa função só pode ser usada em operações transacionais.

## Sintaxe
<a name="ql-functions.exists.syntax"></a>

```
EXISTS ( statement )
```

## Argumentos
<a name="ql-functions.exists.arguments"></a>

*instrução *  
(Obrigatório) A instrução SELECT que a função avalia.  
A instrução SELECT deve especificar uma chave primária completa e alguma outra condição.

## Tipo de retorno
<a name="ql-functions.exists.return-type"></a>

`bool`

## Exemplos
<a name="ql-functions.exists.examples"></a>

```
EXISTS(
    SELECT * FROM "Music" 
    WHERE "Artist" = 'Acme Band' AND "SongTitle" = 'PartiQL Rocks')
```

# Usar a função BEGINS\$1WITH com PartiQL para DynamoDB
<a name="ql-functions.beginswith"></a>

Retorna `TRUE` quando o atributo especificado começa com uma substring específica.

## Sintaxe
<a name="ql-functions.beginswith.syntax"></a>

```
begins_with(path, value )
```

## Argumentos
<a name="ql-functions.beginswith.arguments"></a>

*path*  
(Obrigatório) O nome do atributo ou o caminho do documento a ser usado.

*value*  
(Obrigatório) A string a ser pesquisada.

## Tipo de retorno
<a name="ql-functions.beginswith.return-type"></a>

`bool`

## Exemplos
<a name="ql-functions.beginswith.examples"></a>

```
SELECT * FROM "Orders" WHERE "OrderID"=1 AND begins_with("Address", '7834 24th')
```

# Usar a função MISSING com PartiQL para DynamoDB
<a name="ql-functions.missing"></a>

Retorna `TRUE` quando o item não contém o atributo especificado. Somente operadores de igualdade e desigualdade podem ser usados com esta função.

## Sintaxe
<a name="ql-functions.missing.syntax"></a>

```
 attributename IS | IS NOT  MISSING 
```

## Argumentos
<a name="ql-functions.missing.arguments"></a>

*attributename*  
(Obrigatório) O nome do atributo a ser procurado.

## Tipo de retorno
<a name="ql-functions.missing.return-type"></a>

`bool`

## Exemplos
<a name="ql-functions.missing.examples"></a>

```
SELECT * FROM Music WHERE "Awards" is MISSING
```

# Usar a função ATTRIBUTE\$1TYPE com PartiQL para DynamoDB
<a name="ql-functions.attribute_type"></a>

Retorna `TRUE` quando o atributo no caminho especificado é de um tipo de dados específico.

## Sintaxe
<a name="ql-functions.attribute_type.syntax"></a>

```
attribute_type( attributename, type )
```

## Argumentos
<a name="ql-functions.attribute_type.arguments"></a>

*attributename*  
(Obrigatório) O nome do atributo a ser usado.

*tipo*  
(Obrigatório) O tipo de atributo a ser verificado. Para obter uma lista de valores válidos, consulte [attribute\$1type](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) do DynamoDB.

## Tipo de retorno
<a name="ql-functions.attribute_type.return-type"></a>

`bool`

## Exemplos
<a name="ql-functions.attribute_type.examples"></a>

```
SELECT * FROM "Music" WHERE attribute_type("Artist", 'S')
```

# Usar a função CONTAINS com PartiQL para DynamoDB
<a name="ql-functions.contains"></a>

Retorna `TRUE` quando o atributo especificado pelo caminho é um dos seguintes:
+ Uma String que contém uma substring específica. 
+ Um Set que contém um elemento específico dentro do conjunto.

Para obter mais informações, consulte a função [contains](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) do DynamoDB. 

## Sintaxe
<a name="ql-functions.contains.syntax"></a>

```
contains( path, substring )
```

## Argumentos
<a name="ql-functions.contains.arguments"></a>

*path*  
(Obrigatório) O nome do atributo ou o caminho do documento a ser usado.

*substring*  
(Obrigatório) A substring do atributo ou o membro do conjunto a ser verificado. Para obter mais informações, consulte a função [contains](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) do DynamoDB.

## Tipo de retorno
<a name="ql-functions.contains.return-type"></a>

`bool`

## Exemplos
<a name="ql-functions.contains.examples"></a>

```
SELECT * FROM "Orders" WHERE "OrderID"=1 AND contains("Address", 'Kirkland')
```

# Usar a função SIZE com PartiQL para Amazon DynamoDB
<a name="ql-functions.size"></a>

Retorna um número que representa o tamanho de um atributo em bytes. Veja a seguir os tipos de dados válidos para uso com SIZE. Para obter mais informações, consulte a função [size](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) do DynamoDB.

## Sintaxe
<a name="ql-functions.size.syntax"></a>

```
size( path)
```

## Argumentos
<a name="ql-functions.size.arguments"></a>

*path*  
(Obrigatório) O nome do atributo ou o caminho do documento.   
Para obter os tipos compatíveis, consulte a função [size](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) do DynamoDB.

## Tipo de retorno
<a name="ql-functions.size.return-type"></a>

`int`

## Exemplos
<a name="ql-functions.size.examples"></a>

```
 SELECT * FROM "Orders" WHERE "OrderID"=1 AND size("Image") >300
```

# Operadores aritméticos, comparativos e lógicos de PartiQL para DynamoDB
<a name="ql-operators"></a>

A linguagem PartiQL no Amazon DynamoDB oferece suporte às [instruções SQL padrão](https://www.w3schools.com/sql/sql_operators.asp) a seguir.

**nota**  
Os operadores SQL que não fazem parte desta lista não são aceitas no DynamoDB.

## Operadores aritméticos
<a name="ql-operators.arithmetic"></a>


****  

| Operador | Descrição | 
| --- | --- | 
| \$1 | Adicionar | 
| - | Subtrair | 

## Operadores de comparação
<a name="ql-operators.comparison"></a>


****  

| Operador | Descrição | 
| --- | --- | 
| = | Igual a | 
| <> | Não é igual a | 
| \$1= | Não é igual a | 
| > | Maior que | 
| < | Menor que | 
| >= | Maior ou igual a | 
| <= | Menor ou igual a | 

## Operadores lógicos
<a name="ql-operators.logical"></a>


****  

| Operador | Descrição | 
| --- | --- | 
| AND | TRUE se todas as condições separadas por AND forem TRUE | 
| BETWEEN |  `TRUE` se o operando estiver dentro do intervalo de comparações. Esse operador inclui os limites inferior e superior dos operandos nos quais você o aplica.  | 
| IN | `TRUE` se o operando for igual a um dos valores de uma lista de expressões (no máximo cinquenta valores de atributo hash ou no máximo cem valores de atributo que não sejam chaves). Os resultados são exibidos em páginas com até dez itens. Se a lista `IN` contiver mais valores, será necessário usar o `NextToken` exibido na resposta para recuperar as páginas subsequentes. | 
| IS | TRUE se o operando for um determinado tipo de dados PartiQL, incluindo NULL ou MISSING | 
| NOT | Reverte o valor de uma determinada expressão booleana | 
| OR | TRUE se qualquer uma das condições separadas por OR for TRUE | 

Para obter mais informações sobre como usar operadores lógicos, consulte [Fazer comparações](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.Comparators) e [Avaliações lógicas](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.LogicalEvaluations).

# Executar transações com PartiQL para DynamoDB
<a name="ql-reference.multiplestatements.transactions"></a>

Esta seção descreve como usar transações com a linguagem PartiQL para DynamoDB. As transações PartiQL são limitadas a 100 instruções (ações) no total.

Para obter mais informações sobre transações do DynamoDB, consulte [Gerenciar fluxos de trabalho complexos com transações do DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html).

**nota**  
A transação inteira deve ser composta por instruções de leitura ou instruções de gravação. Não é permitido misturar os dois em uma transação. A função EXISTS é uma exceção. Você pode usá-la para verificar a condição de atributos específicos do item de uma maneira semelhante a `ConditionCheck` na operação [TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems) da API.

**Topics**
+ [Sintaxe](#ql-reference.multiplestatements.transactions.syntax)
+ [Parâmetros](#ql-reference.multiplestatements.transactions.parameters)
+ [Retornar valores](#ql-reference.multiplestatements.transactions.return)
+ [Exemplos](#ql-reference.multiplestatements.transactions.examples)

## Sintaxe
<a name="ql-reference.multiplestatements.transactions.syntax"></a>

```
[
   {
      "Statement":" statement ",
      "Parameters":[
         {
            " parametertype " : " parametervalue "
         }, ...]
   } , ...
]
```

## Parâmetros
<a name="ql-reference.multiplestatements.transactions.parameters"></a>

***instrução***  
(Obrigatório) Uma instrução valida na linguagem PartiQL para DynamoDB.  
A transação inteira deve ser composta por instruções de leitura ou instruções de gravação. Não é permitido misturar os dois em uma transação.

***parametertype***  
(Opcional) Um tipo do DynamoDB, se parâmetros foram usados ao especificar a instrução PartiQL.

***parametervalue***  
(Opcional) Um valor de parâmetro, se parâmetros foram usados ao especificar a instrução PartiQL.

## Retornar valores
<a name="ql-reference.multiplestatements.transactions.return"></a>

Esta instrução não retorna nenhum valor para operações de gravação (INSERT, UPDATE ou DELETE). No entanto, ela retorna valores diferentes para operações de leitura (SELECT) com base nas condições especificadas na cláusula WHERE.

**nota**  
Se qualquer uma das operações singleton INSERT, UPDATE ou DELETE retornar um erro, as transações serão canceladas com a exceção `TransactionCanceledException` e o código de motivo de cancelamento incluirá os erros das operações singleton individuais.

## Exemplos
<a name="ql-reference.multiplestatements.transactions.examples"></a>

O exemplo a seguir executa várias instruções como uma transação.

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

1. Salve o seguinte código JSON em um arquivo chamado 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. Execute o comando a seguir em um prompt de comando.

   ```
   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());
        }
    }

}
```

------

O exemplo a seguir mostra os diferentes valores de retorno quando o DynamoDB lê itens com diferentes condições especificadas na cláusula WHERE.

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

1. Salve o seguinte código JSON em um arquivo chamado 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.  comando a seguir em um prompt de comando.

   ```
   aws dynamodb execute-transaction --transact-statements  file://partiql.json
   ```

1. A resposta a seguir será retornada:

   ```
   {
       "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
           {}
       ]
   }
   ```

------

# Executar operações em lote com PartiQL para DynamoDB
<a name="ql-reference.multiplestatements.batching"></a>

Esta seção descreve como usar instruções em lote com a linguagem PartiQL para DynamoDB.

**nota**  
O lote inteiro deve consistir em instruções de leitura ou instruções de gravação; não é possível misturar ambas em um lote.
`BatchExecuteStatement` e `BatchWriteItem` podem executar mais de 25 instruções por lote.
O `BatchExecuteStatement` faz uso do `BatchGetItem` que utiliza uma lista de chaves primárias em declarações separadas.

**Topics**
+ [Sintaxe](#ql-reference.multiplestatements.batching.syntax)
+ [Parâmetros](#ql-reference.multiplestatements.batching.parameters)
+ [Exemplos](#ql-reference.multiplestatements.batching.examples)

## Sintaxe
<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 "
         }, ...]
   } , ...
]
```

## Parâmetros
<a name="ql-reference.multiplestatements.batching.parameters"></a>

***instrução***  
(Obrigatório) Uma instrução valida na linguagem PartiQL para DynamoDB.  
+ O lote inteiro deve consistir em instruções de leitura ou instruções de gravação; não é possível misturar ambas em um lote.
+ `BatchExecuteStatement` e `BatchWriteItem` podem executar mais de 25 instruções por lote.

***parametertype***  
(Opcional) Um tipo do DynamoDB, se parâmetros foram usados ao especificar a instrução PartiQL.

***parametervalue***  
(Opcional) Um valor de parâmetro, se parâmetros foram usados ao especificar a instrução PartiQL.

## Exemplos
<a name="ql-reference.multiplestatements.batching.examples"></a>

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

1. Salve o seguinte json em um arquivo chamado 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. Execute o comando a seguir em um prompt de comando.

   ```
   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());
        }
    }

}
```

------

# Políticas de segurança do IAM com PartiQL para DynamoDB
<a name="ql-iam"></a>

As seguintes permissões são necessárias:
+ Para ler itens usando PartiQL para DynamoDB, é necessário ter a permissão `dynamodb:PartiQLSelect` na tabela ou no índice.
+ Para inserir itens usando PartiQL para DynamoDB, é necessário ter a permissão `dynamodb:PartiQLInsert` na tabela ou no índice.
+ Para atualizar itens usando PartiQL para DynamoDB, é necessário ter a permissão `dynamodb:PartiQLUpdate` na tabela ou no índice.
+ Para excluir itens usando PartiQL para DynamoDB, é necessário ter a permissão `dynamodb:PartiQLDelete` na tabela ou no índice.

## Exemplo: permitir todas as instruções PartiQL para DynamoDB (Select/Insert/Update/Delete) em uma tabela
<a name="access-policy-ql-iam-example1"></a>

A política do IAM a seguir concede permissões para executar todas as instruções PartiQL para DynamoDB em uma tabela. 

------
#### [ 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"
         ]
      }
   ]
}
```

------

## Exemplo: permitir instruções Select PartiQL para DynamoDB em uma tabela
<a name="access-policy-ql-iam-example2"></a>

A política do IAM a seguir concede permissões para executar a instrução `select` em uma tabela específica.

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

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ]
      }
   ]
}
```

------

## Exemplo: permitir instruções Insert PartiQL para DynamoDB em um índice
<a name="access-policy-ql-iam-example3"></a>

A política do IAM a seguir concede permissões para executar a instrução `insert` em um índice específico. 

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

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music/index/index1"
         ]
      }
   ]
}
```

------

## Exemplo: permitir instruções transacionais PartiQL para DynamoDB somente em uma tabela
<a name="access-policy-ql-iam-example4"></a>

A política do IAM a seguir concede permissões para executar somente instruções transacionais em uma tabela específica. 

------
#### [ 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"
               ]
            }
         }
      }
   ]
}
```

------

## Exemplo: permitir leituras e gravações não transacionais PartiQL para DynamoDB e bloquear leituras e gravações transacionais PartiQL em uma tabela.
<a name="access-policy-ql-iam-example5"></a>

 A política do IAM a seguir concede permissões para executar leituras e gravações não transacionais PartiQL para DynamoDB ao mesmo tempo que bloqueia leituras e gravações transacionais PartiQL para 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"
         ]
      }
   ]
}
```

------

## Exemplo: permitir instruções Select e negar instruções de verificação de tabela completa em PartiQL para DynamoDB
<a name="access-policy-ql-iam-example6"></a>

A política do IAM a seguir concede permissões para executar a instrução `select` em uma tabela específica ao mesmo tempo que bloqueia instruções `select` que resultam em uma verificação de tabela completa.

------
#### [ 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"
         ]
      }
   ]
}
```

------

# Trabalhar com itens: Java
<a name="JavaDocumentAPIItemCRUD"></a>

Você pode usar a API de documentos do AWS SDK para Java para realizar operações create, read, update e delete (CRUD) típicas nos itens do Amazon DynamoDB em uma tabela.

**nota**  
O SDK for Java também fornece um modelo de persistência de objetos que permite que você mapeie suas classes do lado do cliente para tabelas do DynamoDB. Essa abordagem pode reduzir a quantidade de código que você precisa escrever. Para obter mais informações, consulte [Java 1.x: DynamoDBMapper](DynamoDBMapper.md).

Esta seção contém exemplos de Java para executar várias ações de itens da API de documento do Java e vários exemplos funcionais completos.

**Topics**
+ [Colocar um item](#PutDocumentAPIJava)
+ [Obter um item](#JavaDocumentAPIGetItem)
+ [Gravação em lote: colocar e excluir vários itens](#BatchWriteDocumentAPIJava)
+ [Obtenção em lote: obter vários itens](#JavaDocumentAPIBatchGetItem)
+ [Atualizar um item](#JavaDocumentAPIItemUpdate)
+ [Excluir um item](#DeleteMidLevelJava)
+ [Exemplo: operações CRUD usando a API de documento do AWS SDK para Java](JavaDocumentAPICRUDExample.md)
+ [Exemplo: operações em lote usando a API de documento do AWS SDK para Java](batch-operation-document-api-java.md)
+ [Exemplo: tratar atributos do tipo binário usando a API de documento do AWS SDK para Java](JavaDocumentAPIBinaryTypeExample.md)

## Colocar um item
<a name="PutDocumentAPIJava"></a>

O método `putItem` armazena um item em uma tabela. Se o item existe, ele substitui o item inteiro. Em vez de substituir o item inteiro, se você quiser atualizar apenas atributos específicos, use o método `updateItem`. Para obter mais informações, consulte [Atualizar um 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 ]

Siga estas etapas: 

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `Table` para representar a tabela com a qual você deseja trabalhar.

1. Crie uma instância da classe `Item` para representar o novo item. Você deve especificar a chave primária do novo item e seus atributos.

1. Chame o método `putItem` do objeto `Table`, usando o `Item` que você criou na etapa anterior.

O exemplo de código Java a seguir demonstra as tarefas anteriores. O código grava um novo item na tabela `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);
```

No exemplo anterior, o item tem atributos que são escalares (`String`, `Number`, `Boolean`, `Null`), conjuntos (`String Set`) e tipos de documento (`List`, `Map`).

------

### Especificar parâmetros opcionais
<a name="PutItemJavaDocumentAPIOptions"></a>

Além dos parâmetros obrigatórios, você também pode especificar parâmetros opcionais para o método `putItem`. Por exemplo, o seguinte exemplo de código Java usa um parâmetro opcional para especificar uma condição para fazer upload do item. Se a condição que você especificar não for atendida, o AWS SDK para Java lançará uma `ConditionalCheckFailedException`. O exemplo de código especifica os seguintes parâmetros opcionais no método `putItem`:
+ Uma `ConditionExpression` que define as condições para a solicitação. O código define a condição de que o item existente com a mesma chave primária será substituído somente se tiver um atributo ISBN igual a um valor específico. 
+ Um mapa para `ExpressionAttributeValues` que é usado na condição. Nesse caso, existe apenas uma substituição obrigatória: o espaço reservado `:val` na expressão de condição é substituído em tempo de execução pelo valor de ISBN real a ser verificado.

O exemplo a seguir adiciona um novo item de livro usando esses parâmetros opcionais.

**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 e documentos JSON
<a name="PutItemJavaDocumentAPI.JSON"></a>

Você pode armazenar um documento JSON como um atributo em uma tabela do DynamoDB. Para fazer isso, use o método `withJSON` de `Item`. Esse método analisa o documento JSON e mapeia cada elemento em um tipo de dados nativo do DynamoDB.

Suponha que você quisesse armazenar o seguinte documento JSON que contém os fornecedores que podem atender a pedidos de um determinado produto.

**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"
        ]
    }
}
```

Você pode usar o método `withJSON` para armazenar essas informações na tabela `ProductCatalog`, em um atributo `Map` chamado `VendorInfo`. O exemplo de código Java a seguir demonstra como fazer isso.

```
// 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);
```

## Obter um item
<a name="JavaDocumentAPIGetItem"></a>

Para recuperar um único item, use o método `getItem` de um objeto `Table`. Siga estas etapas: 

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `Table` para representar a tabela com a qual você deseja trabalhar.

1. Chame o método `getItem` de instância de `Table`. Você deve especificar a chave primária do item que deseja recuperar.

O exemplo de código Java a seguir demonstra as etapas anteriores. O código obtém o item que tem a chave de partição especificada.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

Item item = table.getItem("Id", 210);
```

### Especificar parâmetros opcionais
<a name="GetItemJavaDocumentAPIOptions"></a>

Além dos parâmetros obrigatórios, você também pode especificar parâmetros opcionais do método `getItem`. Por exemplo, o seguinte exemplo de código Java usa um método opcional para recuperar somente uma lista específica de atributos e para especificar leituras fortemente consistentes. (Para saber mais sobre a consistência de leitura, consulte [Consistência de leitura do DynamoDB](HowItWorks.ReadConsistency.md).)

Você pode usar uma `ProjectionExpression` para recuperar somente atributos ou elementos específicos, em vez de todo o item. A `ProjectionExpression` pode especificar atributos aninhados ou de alto nível, usando caminhos de documentos. Para obter mais informações, consulte [Usar expressões de projeção no DynamoDB](Expressions.ProjectionExpressions.md).

Os parâmetros do método `getItem` não permitem que você especifique consistência de leitura. No entanto, você pode criar uma `GetItemSpec` que dá acesso total a todas as entradas para a operação `GetItem` de baixo nível. O exemplo de código a seguir cria uma `GetItemSpec` e usa essa especificação como entrada para o método `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());
```

 Para imprimir um `Item` em um formato legível, use o método `toJSONPretty`. A saída do exemplo anterior é semelhante à seguinte.

```
{
  "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 e documentos JSON
<a name="GetItemJavaDocumentAPI.JSON"></a>

Na seção [PutItem e documentos JSON](#PutItemJavaDocumentAPI.JSON), você armazenou um documento JSON em um atributo `Map` chamado `VendorInfo`. Você pode usar o método `getItem` para recuperar o documento inteiro no formato JSON. Ou pode usar a notação do caminho do documento para recuperar apenas alguns dos elementos no documento. O exemplo de código Java a seguir demonstra essas técnicas.

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

A saída do exemplo anterior é semelhante à seguinte.

```
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"]}}}
```

**nota**  
Você pode usar o método `toJSON` para converter qualquer item (ou seus atributos) em uma string formatada para JSON. O exemplo de código a seguir recupera vários atributos aninhados e de alto nível e imprime os resultados como JSON.  

```
GetItemSpec spec = new GetItemSpec()
    .withPrimaryKey("Id", 210)
    .withProjectionExpression("VendorInfo.V01, Title, Price");

Item item = table.getItem(spec);
System.out.println(item.toJSON());
```
A saída é semelhante à seguinte.  

```
{"VendorInfo":{"V01":{"Name":"Acme Books","Offices":["Seattle"]}},"Price":30,"Title":"Book 210 Title"}
```

## Gravação em lote: colocar e excluir vários itens
<a name="BatchWriteDocumentAPIJava"></a>

*Gravação em lote* se refere a inserir e excluir vários itens em um lote. O método `batchWriteItem` permite que você insira e exclua vários itens de uma ou mais tabelas em uma única chamada. Veja a seguir as etapas para inserir ou excluir vários itens usando a API de documento do AWS SDK para Java.

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `TableWriteItems` que descreve todas as operações Put e Delete de uma tabela. Se você quiser gravar em várias tabelas com uma única operação de gravação em lote, crie uma instância de `TableWriteItems` por tabela.

1. Chame o método `batchWriteItem`, fornecendo os objetos `TableWriteItems` que você criou na etapa anterior. 

1. Processe a resposta. Você deve verificar se há itens de solicitação não processados retornados na resposta. Isso poderá acontecer se você atingir a cota de throughput provisionado ou por algum outro erro temporário. Além disso, o DynamoDB limita o tamanho da solicitação e o número de operações que você pode especificar em uma solicitação. Se você exceder esses limites, o DynamoDB rejeitará a solicitação. Para obter mais informações, consulte [Cotas no Amazon DynamoDB](ServiceQuotas.md). 

O exemplo de código Java a seguir demonstra as etapas anteriores. O exemplo executa uma operação `batchWriteItem` em duas tabelas: `Forum` e `Thread`. Os objetos `TableWriteItems` correspondentes definem as seguintes ações:
+ Inserir um item na tabela `Forum`.
+ Inserir e excluir um item na tabela `Thread`.

O código chama `batchWriteItem` para executar a operação.

```
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
```

Para obter um exemplo funcional, consulte [Exemplo: operação de gravação em lote usando a API de documento do AWS SDK para Java](batch-operation-document-api-java.md#JavaDocumentAPIBatchWrite). 

## Obtenção em lote: obter vários itens
<a name="JavaDocumentAPIBatchGetItem"></a>

O método `batchGetItem` permite que você recupere vários itens de uma ou mais tabelas. Para recuperar um único item, você pode usar o método `getItem`. 

Siga estas etapas: 

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `TableKeysAndAttributes` que descreve uma lista de valores de chave primária para recuperar de uma tabela. Se você desejar ler em várias tabelas em uma única operação de aquisição em lote, será necessário criar uma instância de `TableKeysAndAttributes` por tabela.

1. Chame o método `batchGetItem`, fornecendo os objetos `TableKeysAndAttributes` que você criou na etapa anterior.

O exemplo de código Java a seguir demonstra as etapas anteriores. O exemplo recupera dois itens da tabela `Forum` e três itens da tabela `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);
    }
}
```

### Especificar parâmetros opcionais
<a name="BatchGetItemJavaDocumentAPIOptions"></a>

Além dos parâmetros obrigatórios, você também pode especificar parâmetros opcionais ao usar `batchGetItem`. Por exemplo, você pode fornecer uma `ProjectionExpression` com cada `TableKeysAndAttributes` que você definir. Isso permite que você especifique os atributos que deseja recuperar da tabela.

O exemplo de código a seguir recupera dois itens da tabela `Forum`. O parâmetro `withProjectionExpression` especifica que apenas o atributo `Threads` deve ser recuperado.

**Example**  

```
TableKeysAndAttributes forumTableKeysAndAttributes = new TableKeysAndAttributes("Forum")
    .withProjectionExpression("Threads");

forumTableKeysAndAttributes.addHashOnlyPrimaryKeys("Name",
    "Amazon S3",
    "Amazon DynamoDB");

BatchGetItemOutcome outcome = dynamoDB.batchGetItem(forumTableKeysAndAttributes);
```

## Atualizar um item
<a name="JavaDocumentAPIItemUpdate"></a>

O método `updateItem` de um objeto `Table` pode atualizar valores de atributo existentes, adicionar novos atributos ou excluir atributos de um item existente. 

O método `updateItem` se comporta da seguinte forma:
+ Se não existir um item (não houver nenhum item na tabela com a chave primária especificada), `updateItem` adicionará um novo item à tabela
+ Se existir um item, `updateItem` executará a atualização conforme especificado pelo parâmetro `UpdateExpression`.

**nota**  
Também é possível "atualizar" um item usando `putItem`. Por exemplo, se você chamar `putItem` para adicionar um item à tabela, mas já existir um item com a chave primária especificada, `putItem` substituirá o item inteiro. Se houver atributos no item existente que não são especificados na entrada, `putItem` removerá esses atributos do item.  
Em geral, recomendamos que você use `updateItem` sempre que desejar modificar quaisquer atributos de item. O método `updateItem` só modifica os atributos de item que você especifica na entrada, e os outros atributos no item permanecem inalterados.

Siga estas etapas: 

1. Crie uma instância da classe `Table` para representar a tabela com a qual você deseja trabalhar.

1. Chame o método `updateTable` de instância de `Table`. Você deve especificar a chave primária do item que deseja recuperar, juntamente com uma `UpdateExpression` que descreve os atributos a serem modificados e como modificá-los.

O exemplo de código Java a seguir demonstra as tarefas anteriores. O código atualiza um item na tabela `ProductCatalog`. Ele adiciona um novo autor ao conjunto de `Authors` e exclui o atributo `ISBN` existente. Ele também reduz o preço por um.

Um mapa `ExpressionAttributeValues` é usado na `UpdateExpression`. Os espaços reservados `:val1` e `:val2` serão substituídos em tempo de execução pelos valores reais de `Authors` e `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);
```

### Especificar parâmetros opcionais
<a name="UpdateItemJavaDocumentAPIOptions"></a>

Além dos parâmetros obrigatórios, você também pode especificar parâmetros opcionais para o método `updateItem`, incluindo uma condição que deve ser atendida para que a atualização ocorra. Se a condição que você especificar não for atendida, o AWS SDK para Java lançará uma `ConditionalCheckFailedException`. Por exemplo, o seguinte exemplo de código Java atualiza condicionalmente o preço de item de um livro para 25. Ele especifica uma `ConditionExpression` que declara que o preço deve ser atualizado somente se o preço existente for 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);
```

### Contador atômico
<a name="AtomicCounterJavaDocumentAPI"></a>

Você pode usar `updateItem` para implementar um contador atômico, onde pode aumentar ou reduzir o valor de um atributo existente sem interferir em outras solicitações de gravação. Para aumentar um contador atômico, use uma `UpdateExpression` com uma ação `set` para adicionar um valor numérico a um atributo existente do tipo `Number`.

O exemplo de código a seguir demonstra isso incrementando o atributo `Quantity` em um. Ele também demonstra o uso do parâmetro `ExpressionAttributeNames` em uma `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);
```

## Excluir um item
<a name="DeleteMidLevelJava"></a>

O método `deleteItem` exclui um item de uma tabela. É necessário fornecer a chave primária do item que você deseja excluir.

Siga estas etapas: 

1. Crie uma instância do cliente `DynamoDB`.

1. Chame o método `deleteItem`, fornecendo a chave do item que você deseja excluir. 

O exemplo de código Java a seguir demonstra essas tarefas.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

DeleteItemOutcome outcome = table.deleteItem("Id", 101);
```

### Especificar parâmetros opcionais
<a name="DeleteItemJavaDocumentAPIOptions"></a>

Você pode especificar parâmetros opcionais para `deleteItem`. Por exemplo, o seguinte exemplo de código Java especifica uma `ConditionExpression` que declara que um item de livro em `ProductCatalog` só pode ser excluído se o livro não estiver mais em publicação (o atributo `InPublication` é falso).

**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);
```

# Exemplo: operações CRUD usando a API de documento do AWS SDK para Java
<a name="JavaDocumentAPICRUDExample"></a>

O exemplo de código a seguir ilustra operações CRUD em um item do Amazon DynamoDB. O exemplo cria um item, o recupera, executa várias atualizações e, por fim, o exclui.

**nota**  
O SDK for Java também fornece um modelo de persistência de objetos que permite que você mapeie suas classes do lado do cliente para tabelas do DynamoDB. Essa abordagem pode reduzir a quantidade de código que você precisa escrever. Para obter mais informações, consulte [Java 1.x: DynamoDBMapper](DynamoDBMapper.md).

**nota**  
Este exemplo de código pressupõe que você já carregou dados no DynamoDB para sua conta seguindo as instruções na seção [Criar tabelas e carregar dados para exemplos de código no DynamoDB](SampleData.md).  
Para obter instruções passo a passo sobre como executar o exemplo a seguir, consulte [Exemplos de código 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());
        }
    }
}
```

# Exemplo: operações em lote usando a API de documento do AWS SDK para Java
<a name="batch-operation-document-api-java"></a>

Esta seção fornece exemplos de operações de gravação e aquisição em lote no Amazon DynamoDB usando a API de documentos do AWS SDK para Java.

**nota**  
O SDK for Java também fornece um modelo de persistência de objetos que permite que você mapeie suas classes do lado do cliente para tabelas do DynamoDB. Essa abordagem pode reduzir a quantidade de código que você precisa escrever. Para obter mais informações, consulte [Java 1.x: DynamoDBMapper](DynamoDBMapper.md).

**Topics**
+ [Exemplo: operação de gravação em lote usando a API de documento do AWS SDK para Java](#JavaDocumentAPIBatchWrite)
+ [Exemplo: operação de obtenção em lote usando a API de documento do AWS SDK para Java](#JavaDocumentAPIBatchGet)

## Exemplo: operação de gravação em lote usando a API de documento do AWS SDK para Java
<a name="JavaDocumentAPIBatchWrite"></a>

O exemplo de código Java a seguir usa o método `batchWriteItem` para executar as operações Put e Delete a seguir:
+ Inserir um item na tabela `Forum`.
+ Inserir e excluir um item da tabela `Thread`. 

Você pode especificar quantas solicitações de inserção e exclusão desejar em uma ou mais tabelas ao criar sua solicitação de gravação em lote. No entanto, `batchWriteItem` limita o tamanho de uma solicitação de gravação em lote e o número de operações Put e Delete em uma única operação. Se a sua solicitação ultrapassar esses limites, ela será rejeitada. Se a sua tabela não tiver throughput provisionado suficiente para servir a essa solicitação, os itens de solicitação não processados serão retornados na resposta. 

O exemplo a seguir verifica a resposta para conferir se existem itens de solicitação não processados. Se houver, ele retorna e reenvia a solicitação `batchWriteItem` com itens não processados na solicitação. Se você tiver seguido os exemplos neste guia, já deverá ter criado as tabelas `Forum` e `Thread`. Você também pode criar essas tabelas e fazer upload dos dados de exemplo de forma programática. Para obter mais informações, consulte [Criar exemplos de tabelas e carregar dados usando o AWS SDK para Java](AppendixSampleDataCodeJava.md).

Para obter instruções detalhadas sobre como testar o exemplo a seguir, consulte [Exemplos de código 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);
        }

    }

}
```

## Exemplo: operação de obtenção em lote usando a API de documento do AWS SDK para Java
<a name="JavaDocumentAPIBatchGet"></a>

O exemplo de código Java a seguir usa o método `batchGetItem` para recuperar vários itens das tabelas `Forum` e `Thread`. A `BatchGetItemRequest` especifica os nomes de tabela e uma lista de chaves de cada item a ser obtido. O exemplo processa a resposta, imprimindo os itens recuperados.

**nota**  
Este exemplo de código pressupõe que você já carregou dados no DynamoDB para sua conta seguindo as instruções na seção [Criar tabelas e carregar dados para exemplos de código no DynamoDB](SampleData.md).  
Para obter instruções passo a passo sobre como executar o exemplo a seguir, consulte [Exemplos de código 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());
        }

    }

}
```

# Exemplo: tratar atributos do tipo binário usando a API de documento do AWS SDK para Java
<a name="JavaDocumentAPIBinaryTypeExample"></a>

O exemplo de código Java a seguir ilustra o tratamento de atributos do tipo binário. O exemplo adiciona um item à tabela `Reply`. O item inclui um atributo do tipo binário (`ExtendedMessage`) que armazena dados compactados. Em seguida, o exemplo recupera um item e imprime todos os valores do atributo. Para ilustração, o exemplo usa a classe `GZIPOutputStream` para compactar um stream de exemplo e atribuí-lo ao atributo `ExtendedMessage`. Quando o atributo binário é recuperado, ele é descompactado usando a classe `GZIPInputStream`. 

**nota**  
O SDK for Java também fornece um modelo de persistência de objetos que permite que você mapeie suas classes do lado do cliente para tabelas do DynamoDB. Essa abordagem pode reduzir a quantidade de código que você precisa escrever. Para obter mais informações, consulte [Java 1.x: DynamoDBMapper](DynamoDBMapper.md).

Se você tiver seguido a seção [Criar tabelas e carregar dados para exemplos de código no DynamoDB](SampleData.md), já deverá ter criado a tabela `Reply`. Você também pode criar essa tabela de forma programática. Para obter mais informações, consulte [Criar exemplos de tabelas e carregar dados usando o AWS SDK para Java](AppendixSampleDataCodeJava.md).

Para obter instruções detalhadas sobre como testar o exemplo a seguir, consulte [Exemplos de código 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;
    }
}
```

# Trabalhar com itens: .NET
<a name="LowLevelDotNetItemCRUD"></a>

Você pode usar a API de baixo nível do AWS SDK para .NET para executar operações típicas create, read, update, delete (CRUD - criação, leitura, atualização e exclusão) em um item de uma tabela. Veja a seguir as etapas comuns que você segue para executar operações CRUD em dados usando a API de baixo nível do .NET:

1. Crie uma instância da classe `AmazonDynamoDBClient` (o cliente).

1. Forneça os parâmetros necessários específicos à operação em um objeto de solicitação correspondente.

   Por exemplo, use o objeto de solicitação `PutItemRequest` ao carregar um item e use o objeto de solicitação `GetItemRequest` ao recuperar um item existente. 

   Você pode usar o objeto de solicitação para fornecer tanto parâmetros necessários quanto opcionais. 

1. Execute o método apropriado fornecido pelo cliente, transmitindo o objeto de solicitação que você criou na etapa anterior. 

   O cliente `AmazonDynamoDBClient` fornece os métodos `PutItem`, `GetItem`, `UpdateItem` e `DeleteItem` para as operações CRUD.

**Topics**
+ [Colocar um item](#PutItemLowLevelAPIDotNet)
+ [Obter um item](#GetItemLowLevelDotNET)
+ [Atualizar um item](#UpdateItemLowLevelDotNet)
+ [Contador atômico](#AtomicCounterLowLevelDotNet)
+ [Excluir um item](#DeleteMidLevelDotNet)
+ [Gravação em lote: colocar e excluir vários itens](#BatchWriteLowLevelDotNet)
+ [Obtenção em lote: obter vários itens](#BatchGetLowLevelDotNet)
+ [Exemplo: operações CRUD usando a API de baixo nível AWS SDK para .NET](LowLevelDotNetItemsExample.md)
+ [Exemplo: operações em lote usando a API de baixo nível do AWS SDK para .NET](batch-operation-lowlevel-dotnet.md)
+ [Exemplo: tratar atributos do tipo binário usando a API de baixo nível do AWS SDK para .NET](LowLevelDotNetBinaryTypeExample.md)

## Colocar um item
<a name="PutItemLowLevelAPIDotNet"></a>

O método `PutItem` carrega um item em uma tabela. Se o item existe, ele substitui o item inteiro.

**nota**  
Em vez de substituir o item inteiro, se você quiser atualizar apenas atributos específicos, use o método `UpdateItem`. Para obter mais informações, consulte [Atualizar um item](#UpdateItemLowLevelDotNet).

Veja a seguir as etapas para carregar um item usando a API do SDK do .NET de baixo nível:

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Forneça os parâmetros necessários, criando uma instância da classe `PutItemRequest`.

   Para inserir item, você deve fornecer o nome da tabela e o item. 

1. Execute o método `PutItem` fornecendo o objeto `PutItemRequest` que você criou na etapa anterior.

O exemplo de C\$1 a seguir demonstra as etapas anteriores. O exemplo faz upload de um item para a tabela `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);
```

No exemplo anterior, você faz upload de um item de livro que tem os atributos `Id`, `Title`, `ISBN` e `Authors`. Observe que `Id` é um atributo de tipo numérico, e todos os outros atributos são do tipo string. Autores é um conjunto `String`.

### Especificar parâmetros opcionais
<a name="PutItemLowLevelAPIDotNetOptions"></a>

Você também pode fornecer parâmetros opcionais usando o objeto `PutItemRequest`, conforme mostrado no seguinte exemplo de C\$1. O exemplo especifica os seguintes parâmetros opcionais:
+ `ExpressionAttributeNames`, `ExpressionAttributeValues` e `ConditionExpression` especificam que o item pode ser substituído somente se o item existente tiver o atributo ISBN com um valor específico.
+ `ReturnValues`o parâmetro para solicitar o item antigo na resposta.

**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);
```

Para obter mais informações, consulte [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html).

## Obter um item
<a name="GetItemLowLevelDotNET"></a>

O método `GetItem` recupera um item.

**nota**  
Para recuperar vários itens, você pode usar o método `BatchGetItem`. Para obter mais informações, consulte [Obtenção em lote: obter vários itens](#BatchGetLowLevelDotNet).

Veja a seguir as etapas para recuperar um item existente usando a API do AWS SDK para .NET de baixo nível.

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Forneça os parâmetros necessários, criando uma instância da classe `GetItemRequest`.

   Para obter um item, você deve fornecer o nome da tabela e a chave primária desse item. 

1. Execute o método `GetItem` fornecendo o objeto `GetItemRequest` que você criou na etapa anterior.

O exemplo de C\$1 a seguir demonstra as etapas anteriores. O exemplo recupera um item da tabela `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.
```

### Especificar parâmetros opcionais
<a name="GetItemLowLevelDotNETOptions"></a>

Você também pode fornecer parâmetros opcionais usando o objeto `GetItemRequest`, conforme mostrado no seguinte exemplo de C\$1. O exemplo especifica os parâmetros opcionais a seguir:
+ `ProjectionExpression`o parâmetro para especificar os atributos a serem recuperados.
+ `ConsistentRead`o parâmetro para realizar uma leitura fortemente consistente. Para saber mais sobre a consistência de leitura, consulte [Consistência de leitura do DynamoDB](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;
```

Para obter mais informações, consulte [GetItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html).

## Atualizar um item
<a name="UpdateItemLowLevelDotNet"></a>

O método `UpdateItem` atualiza um item existente, se estiver presente. É possível usar a operação `UpdateItem` para atualizar valores de atributos existentes, adicionar novos atributos ou excluir atributos da coleção existente. Se o item que tem a chave primária especificada não for encontrado, ela adicionará um novo item.

A operação `UpdateItem` usa as seguintes diretrizes:
+ Se o item não existir, o `UpdateItem` adicionará um novo item usando a chave primária especificada na entrada.
+ Se o item existir, o `UpdateItem` aplicará as atualizações da seguinte maneira:
  + Substitui os valores de atributos existentes pelos valores na atualização.
  + Se o atributo que você fornecer na entrada não existir, ele adicionará um novo atributo ao item.
  + Se o valor do atributo de entrada for nulo, ele excluirá o atributo, se estiver presente. 
  + Se você usar `ADD` para a `Action`, poderá adicionar valores a um conjunto existente (conjunto de strings ou números) ou adicionar (usar um número positivo) ou subtrair (usar um número negativo) matematicamente com base no valor de atributo numérico existente.

**nota**  
A operação `PutItem` também pode realizar uma atualização. Para obter mais informações, consulte [Colocar um item](#PutItemLowLevelAPIDotNet). Por exemplo, se você chamar `PutItem` para fazer upload de um item, e a chave primária existir, a operação `PutItem` substituirá o item inteiro. Se houver atributos no item existente e esses atributos não forem especificados na entrada, a operação `PutItem` os excluirá. No entanto, `UpdateItem` só atualiza os atributos de entrada especificados. Outros atributos existentes desse item permanecerão inalterados. 

Veja a seguir as etapas para atualizar um item existente usando a API do SDK do .NET de baixo nível:

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Forneça os parâmetros necessários, criando uma instância da classe `UpdateItemRequest`.

   Este é o objeto de solicitação em que você descreve todas as atualizações, por exemplo, adiciona atributos, atualizar atributos existentes ou excluir atributos. Para excluir um atributo existente, especifique o nome desse atributo com um valor nulo. 

1. Execute o método `UpdateItem` fornecendo o objeto `UpdateItemRequest` que você criou na etapa anterior. 

O exemplo de código C\$1 a seguir demonstra as etapas anteriores. O exemplo de código atualiza um item na tabela `ProductCatalog`. Ele adiciona um novo autor à coleção `Authors` e exclui o atributo `ISBN` existente. Ele também reduz o preço por um.



```
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);
```

### Especificar parâmetros opcionais
<a name="UpdateItemLowLevelDotNETOptions"></a>

Você também pode fornecer parâmetros opcionais usando o objeto `UpdateItemRequest`, conforme mostrado no seguinte exemplo de C\$1. Especifica os parâmetros opcionais a seguir:
+ `ExpressionAttributeValues` e `ConditionExpression` para especificar que o preço apenas poderá ser atualizado se o preço existente for 20,00.
+ `ReturnValues`o parâmetro para solicitar o item atualizado na resposta. 

**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);
```

Para obter mais informações, consulte [UpdateItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html). 

## Contador atômico
<a name="AtomicCounterLowLevelDotNet"></a>

Você pode usar `updateItem` para implementar um contador atômico, onde pode aumentar ou reduzir o valor de um atributo existente sem interferir em outras solicitações de gravação. Para atualizar um contador atômico, use `updateItem` com um atributo do tipo `Number` no parâmetro `UpdateExpression` e `ADD` como a `Action`.

O exemplo de código a seguir demonstra isso incrementando o atributo `Quantity` em um.

```
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);
```

## Excluir um item
<a name="DeleteMidLevelDotNet"></a>

O método `DeleteItem` exclui um item de uma tabela. 

Veja a seguir as etapas para excluir um item usando a API de SDK do .NET de baixo nível. 

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Forneça os parâmetros necessários, criando uma instância da classe `DeleteItemRequest`.

    Para excluir um item, o nome da tabela e a chave primária desse item são necessários. 

1. Execute o método `DeleteItem` fornecendo o objeto `DeleteItemRequest` que você criou na etapa anterior. 

**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);
```

### Especificar parâmetros opcionais
<a name="DeleteItemLowLevelDotNETOptions"></a>

Você também pode fornecer parâmetros opcionais usando o objeto `DeleteItemRequest`, conforme mostrado no seguinte exemplo de código C\$1. Especifica os parâmetros opcionais a seguir:
+ `ExpressionAttributeValues` e `ConditionExpression` para especificar que o item de livro apenas poderá ser excluído se não estiver mais em publicação (se o valor do atributo InPublication for false). 
+ `ReturnValues`o parâmetro para solicitar o item excluído na resposta.

**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);
```

Para obter mais informações, consulte [DeleteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DeleteItem.html).

## Gravação em lote: colocar e excluir vários itens
<a name="BatchWriteLowLevelDotNet"></a>

*Gravação em lote* se refere a inserir e excluir vários itens em um lote. O método `BatchWriteItem` permite que você insira e exclua vários itens de uma ou mais tabelas em uma única chamada. Veja a seguir as etapas para recuperar vários itens usando a API de SDK do .NET de baixo nível.

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Descreva todas as operações de inserção e exclusão, criando uma instância da classe `BatchWriteItemRequest`.

1. Execute o método `BatchWriteItem` fornecendo o objeto `BatchWriteItemRequest` que você criou na etapa anterior.

1. Processe a resposta. Você deve verificar se há itens de solicitação não processados retornados na resposta. Isso poderá acontecer se você atingir a cota de throughput provisionado ou por algum outro erro temporário. Além disso, o DynamoDB limita o tamanho da solicitação e o número de operações que você pode especificar em uma solicitação. Se você exceder esses limites, o DynamoDB rejeitará a solicitação. Para obter mais informações, consulte [BatchWriteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html). 

O exemplo de código C\$1 a seguir demonstra as etapas anteriores. O exemplo cria uma `BatchWriteItemRequest` para realizar as seguintes operações de gravação:
+ Inserir um item na tabela `Forum`.
+ Inserir e excluir um item da tabela `Thread`.

Em seguida, o código executa `BatchWriteItem` para realizar uma operação em lote.

```
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);
```

Para obter um exemplo funcional, consulte [Exemplo: operações em lote usando a API de baixo nível do AWS SDK para .NET](batch-operation-lowlevel-dotnet.md). 

## Obtenção em lote: obter vários itens
<a name="BatchGetLowLevelDotNet"></a>

O método `BatchGetItem` permite que você recupere vários itens de uma ou mais tabelas. 

**nota**  
Para recuperar um único item, você pode usar o método `GetItem`. 

Veja a seguir as etapas para recuperar vários itens usando a API do AWS SDK para .NET de baixo nível.

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Forneça os parâmetros necessários, criando uma instância da classe `BatchGetItemRequest`.

   Para recuperar vários itens, o nome da tabela e uma lista de valores de chave primária são necessários. 

1. Execute o método `BatchGetItem` fornecendo o objeto `BatchGetItemRequest` que você criou na etapa anterior.

1. Processe a resposta. Você deve verificar se houve chaves não processadas, o que pode acontecer caso você tenha atingido a cota de throughput provisionado ou caso tenha ocorrido algum outro erro temporário.

O exemplo de código C\$1 a seguir demonstra as etapas anteriores. O exemplo recupera itens de duas tabelas, `Forum` e `Thread`. A solicitação especifica dois itens na tabela `Forum` e três itens em `Thread`. A resposta inclui itens de ambas as tabelas. O código mostra como você pode processar a resposta.



```
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);
}
```



### Especificar parâmetros opcionais
<a name="BatchGetItemLowLevelDotNETOptions"></a>

Você também pode fornecer parâmetros opcionais usando o objeto `BatchGetItemRequest`, conforme mostrado no seguinte exemplo de código C\$1. O exemplo recupera dois itens da tabela `Forum`. Ele especifica o parâmetro opcional a seguir:
+  `ProjectionExpression`o parâmetro para especificar os atributos a serem recuperados.

**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);
```

Para obter mais informações, consulte [BatchGetItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html). 

# Exemplo: operações CRUD usando a API de baixo nível AWS SDK para .NET
<a name="LowLevelDotNetItemsExample"></a>

O exemplo de código C\$1 a seguir ilustra operações CRUD em um item do Amazon DynamoDB. O exemplo adiciona um item à tabela `ProductCatalog`, recupera-o, executa várias atualizações e, por fim, exclui o item. Se você não criou essa tabela, também pode criá-la de maneira programática. Para obter mais informações, consulte [Criar exemplos de tabelas e carregar dados usando o AWS SDK para .NET](AppendixSampleDataCodeDotNET.md).

Para obter instruções detalhadas sobre como testar o exemplo a seguir, consulte [Exemplos de código .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("************************************************");
        }
    }
}
```

# Exemplo: operações em lote usando a API de baixo nível do AWS SDK para .NET
<a name="batch-operation-lowlevel-dotnet"></a>

**Topics**
+ [Exemplo: operação de gravação em lote usando a API de baixo nível do AWS SDK para .NET](#batch-write-low-level-dotnet)
+ [Exemplo: operação de obtenção em lote usando a API de baixo nível do AWS SDK para .NET](#LowLevelDotNetBatchGet)

Esta seção fornece exemplos de operações em lote, *gravação em lote* e *aquisição em lote* aceitas pelo Amazon DynamoDB.

## Exemplo: operação de gravação em lote usando a API de baixo nível do AWS SDK para .NET
<a name="batch-write-low-level-dotnet"></a>

O exemplo de código C\$1 a seguir usa o método `BatchWriteItem` para executar as operações de inserção e exclusão a seguir:
+ Inserir um item na tabela `Forum`.
+ Inserir e excluir um item da tabela `Thread`. 

Você pode especificar quantas solicitações de inserção e exclusão desejar em uma ou mais tabelas ao criar sua solicitação de gravação em lote. No entanto, `BatchWriteItem` do DynamoDB limita o tamanho de uma solicitação de gravação em lote e o número de operações Put e Delete em uma única operação. Para obter mais informações, consulte [BatchWriteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html). Se a sua solicitação ultrapassar esses limites, ela será rejeitada. Se a sua tabela não tiver throughput provisionado suficiente para servir a essa solicitação, os itens de solicitação não processados serão retornados na resposta. 

O exemplo a seguir verifica a resposta para conferir se existem itens de solicitação não processados. Se houver, ele retorna e reenvia a solicitação `BatchWriteItem` com itens não processados na solicitação. Você também pode criar essas tabelas de exemplo e carregar dados de exemplo de forma programática. Para obter mais informações, consulte [Criar exemplos de tabelas e carregar dados usando o AWS SDK para .NET](AppendixSampleDataCodeDotNET.md).

Para obter instruções detalhadas sobre como testar o exemplo a seguir, consulte [Exemplos de código .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);
        }
    }
}
```

## Exemplo: operação de obtenção em lote usando a API de baixo nível do AWS SDK para .NET
<a name="LowLevelDotNetBatchGet"></a>

O exemplo de código C\$1 a seguir usa o método `BatchGetItem` para recuperar vários itens das tabelas `Forum` e `Thread` no Amazon DynamoDB. A `BatchGetItemRequest` especifica os nomes de tabelas e uma lista de chaves primárias para cada tabela. O exemplo processa a resposta, imprimindo os itens recuperados. 

Para obter instruções detalhadas sobre como testar o exemplo a seguir, consulte [Exemplos de código .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("************************************************");
        }
    }
}
```

# Exemplo: tratar atributos do tipo binário usando a API de baixo nível do AWS SDK para .NET
<a name="LowLevelDotNetBinaryTypeExample"></a>

O exemplo de código C\$1 a seguir ilustra a manipulação de atributos do tipo Binário. O exemplo adiciona um item à tabela `Reply`. O item inclui um atributo do tipo binário (`ExtendedMessage`) que armazena dados compactados. Em seguida, o exemplo recupera um item e imprime todos os valores do atributo. Para ilustração, o exemplo usa a classe `GZipStream` para compactar um stream de exemplo e designá-lo ao atributo `ExtendedMessage`. Em seguida, ele descompacta esse stream ao imprimir o valor do atributo. 

Para obter instruções passo a passo sobre como testar o exemplo a seguir, consulte [Exemplos de código .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();
            }
        }
    }
}
```

# Melhorar o acesso aos dados com índices secundários no DynamoDB
<a name="SecondaryIndexes"></a>

O Amazon DynamoDB dá acesso rápido a itens em uma tabela ao especificar valores de chave primária. No entanto, muitos aplicativos podem se beneficiar por terem uma ou mais chaves secundárias (ou alternativas) disponíveis, para permitir acesso eficiente aos dados com atributos que não sejam a chave primária. Para resolver isso, você pode criar um ou mais índices secundários em uma tabela e emitir solicitações de `Query` ou de `Scan` nesses índices.

Um *índice secundário* é uma estrutura de dados que contém um subconjunto de atributos de uma tabela, juntamente com uma chave alternativa para oferecer suporte a operações `Query`. Você pode recuperar dados do índice usando uma `Query`, de maneira muito semelhante ao uso de uma `Query` com uma tabela. Uma tabela pode ter vários índices secundários, o que permite que seus aplicativos tenham acesso a muitos padrões de consulta diferentes.

**nota**  
Você também pode `Scan` um índice, da mesma forma como poderia `Scan` uma tabela.   
Atualmente, o acesso entre contas para operações de verificação de índice secundário não é aceito em [políticas baseadas em recursos](access-control-resource-based.md).

Cada índice secundário está associado a exatamente uma tabela, da qual ele obtém seus dados. Ela é chamada de *tabela base* para o índice. Ao criar um índice, você define uma chave alternativa para ele (chave de partição e chave de classificação). Você também define os atributos a serem *projetados*, ou copiados, da tabela-base para o índice. O DynamoDB copia esses atributos para o índice, juntamente com os atributos de chave primária da tabela-base. Você pode consultar ou verificar o índice como faria com qualquer tabela. 

Cada índice secundário é automaticamente mantido pelo DynamoDB. Quando você adiciona, modifica ou exclui itens na tabela base, todos os índices dessa tabela também são atualizados para refletir essas alterações.

O DynamoDB oferece suporte a dois tipos de índices secundários:
+ **[Índice secundário global](GSI.html)**: um índice com uma chave de partição e uma chave de classificação que podem ser diferentes daquelas contidas na tabela-base. Um índice secundário global é considerado “global” porque as consultas no índice podem abranger todos os dados em uma tabela base, além de todas as partições. O índice secundário global é armazenado em seu próprio espaço de partição longe da tabela-base e é dimensionado separadamente da tabela-base.
+ **[Índice secundário local](LSI.html)**: um índice que tem a mesma chave de partição que a tabela-base, mas uma chave de classificação diferente. Um índice secundário local é “local” no sentido de que cada partição de um índice secundário local tem a determinação de escopo para uma partição de tabela base com o mesmo valor de chave de partição.

Para ver uma comparação entre índices secundários globais e índices secundários locais, assista a este vídeo.

[![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**
+ [Como usar índices secundários globais no DynamoDB](GSI.md)
+ [Índices secundários locais](LSI.md)

Você deve considerar os requisitos do seu aplicativo ao determinar qual tipo de índice usar. A tabela a seguir mostra as principais diferenças entre um índice secundário global e um índice secundário local.


****  

| Característica | Índice secundário global | Índice secundário local | 
| --- | --- | --- | 
| Esquema de chaves | A chave primária de um índice secundário global pode ser simples (chave de partição) ou composta (chave de partição e chave de classificação). | A chave primária de um índice secundário local deve ser composta (chave de partição e chave de classificação). | 
| Atributos de chaves | A chave de partição e a chave de classificação (se presente) do índice podem ser qualquer atributo da tabela base do tipo String, Número ou Binário. | A chave de partição do índice é o mesmo atributo que a chave de partição da tabela base. A chave de classificação pode ser qualquer atributo da tabela base do tipo String, Número ou Binário. | 
| Restrições de tamanho por valor de chave de partição | Não há restrições de tamanho para índices secundários globais. | Para cada valor de chave de partição, o tamanho total de todos os itens indexados deve ser 10 GB ou menos. | 
| Operações de índice online | Você pode criar índices secundários globais ao mesmo tempo que cria uma tabela. Você também pode adicionar um novo índice secundário global a uma tabela ou então excluí-lo. Para obter mais informações, consulte [Gerenciar índices secundários globais no DynamoDB](GSI.OnlineOps.md).  | Você pode criar índices secundários locais ao mesmo tempo que cria uma tabela. Não é possível adicionar um índice secundário local a uma tabela existente nem excluir índices secundários existentes. | 
| Consultas e partições | Um índice secundário global permite que você consulte a tabela inteira, em todas as partições.  | Um índice secundário local permite consultar uma única partição, conforme especificado pelo valor da chave de partição na consulta. | 
| Consistência de leituras | As consultas em índices secundários globais oferecem suporte somente à consistência final. | Ao consultar um índice secundário local, você pode escolher consistência final ou coerência forte. | 
| Consumo de throughput provisionado | Cada índice secundário global tem suas próprias configurações de throughput provisionado para atividades de leitura e gravação. Consultas ou verificações em um índice secundário global consumem unidades de capacidade do índice, e não da tabela-base. O mesmo vale para atualizações de índices secundários globais devido a gravações de tabelas. Um índice secundário global associado a tabelas globais consome unidades de capacidade de gravação.  | Consultas ou verificações em um índice secundário local consomem unidades de capacidade de leitura da tabela-base. Quando você grava em uma tabela, seus índices secundários locais também são atualizados. Essas atualizações consomem unidades de capacidade de gravação da tabela-base. Um índice secundário local associado a tabelas globais consome unidades de capacidade de gravação replicadas. | 
| Atributos projetados | Com consultas ou verificações em um índice secundário global, você pode solicitar somente os atributos que estão projetados no índice. O DynamoDB não busca atributos da tabela. | Se você consultar ou verificar um índice secundário local, poderá solicitar atributos que não estão projetados no índice. O DynamoDB buscará automaticamente os atributos da tabela. | 

Se quiser criar mais de uma tabela com índices secundários, você deverá fazer isso sequencialmente. Por exemplo, você poderia criar a primeira tabela e esperar até que ela entrasse no estado `ACTIVE`. Em seguida, você criaria a seguinte tabela e esperaria até que ela entrasse no estado `ACTIVE` e assim por diante. Se você tentar criar mais de uma tabela ao mesmo tempo com um índice secundário, o DynamoDB retornará uma `LimitExceededException`.

Cada índice secundário usa a mesma [classe de tabela](HowItWorks.TableClasses.html) e [modo de capacidade](capacity-mode.md) da tabela-base à qual está associado. Para cada índice secundário, é necessário especificar o seguinte:
+ O tipo de índice a ser criado: índice secundário global ou índice secundário local.
+ Um nome para o índice. As regras de nomenclatura de índices são iguais às de tabelas, conforme listado em [Cotas no Amazon DynamoDB](ServiceQuotas.md). O nome deve ser exclusivo para a tabela-base à qual ele está associado, mas você pode usar o mesmo nome para índices que estão associados a diferentes tabelas-base.
+ O esquema de chaves do índice. Cada atributo no esquema de chaves do índice deve ser um atributo de nível superior do tipo `String`. `Number` ou `Binary`. Outros tipos de dados, incluindo documentos e conjuntos, não são permitidos. Outros requisitos para o esquema de chaves dependem do tipo de índice: 
  + Para um índice secundário global, a chave de partição pode ser qualquer atributo escalar da tabela-base. Uma chave de classificação é opcional e também pode ser qualquer atributo escalar da tabela-base.
  + Para um índice secundário local, a chave de partição deve igual à chave de partição da tabela-base, e a chave de classificação deve ser um atributo da tabela-base não relacionado a chaves.
+ Atributos adicionais, se houver, a serem projetados da tabela-base no índice. Esses atributos são adicionais aos atributos de chave da tabela, que são automaticamente projetados em cada índice. Você pode projetar atributos de qualquer tipo de dados, incluindo escalares, documentos e conjuntos.
+ As configurações de throughput provisionado para o índice, se necessário:
  + Para um índice secundário global, você deve especificar configurações de unidades de capacidade de gravação. Essas configurações de throughput provisionado são independentes das configurações da tabela-base.
  + Para um índice secundário local, não é necessário especificar configurações de unidades de capacidade de gravação. Qualquer operação de leitura e gravação em um índice secundário extrai das configurações de throughput provisionado de sua tabela-base.

Para obter a flexibilidade máxima nas consultas, é possível criar até 20 índices secundários globais (cota padrão) e até 5 índices secundários locais por tabela.

Para obter uma listagem detalhada de índices secundários em uma tabela, use a operação `DescribeTable`. `DescribeTable` retorna o nome, o tamanho de armazenamento e as contagens de itens de cada índice secundário na tabela. Esses valores não são atualizados em tempo real, mas aproximadamente a cada seis horas.

Você pode acessar os dados em um índice secundário usando a operação `Query` ou `Scan`. Você deve especificar o nome da tabela-base e o nome do índice que deseja usar, os atributos a serem retornados nos resultados e qualquer expressão de condição a ser aplicada. O DynamoDB pode retornar os resultados em ordem crescente ou decrescente.

Quando uma tabela é excluída, todos os índices associados a ela também são excluídos.

Para ver as práticas recomendadas, consulte [Práticas recomendadas para uso de índices secundários no DynamoDB](bp-indexes.md).

# Como usar índices secundários globais no DynamoDB
<a name="GSI"></a>

Alguns aplicativos talvez precisem executar muitos tipos de consultas, usando uma variedade de atributos diferentes como critérios de consulta. Para oferecer suporte a esses requisitos, você pode criar um ou mais *índices secundários globais* e emitir solicitações `Query` para esses índices no Amazon DynamoDB.

**Topics**
+ [Cenário: Uso de um índice secundário global](#GSI.scenario)
+ [Projeções de atributo](#GSI.Projections)
+ [Esquema de chave de vários atributos](#GSI.MultiAttributeKeys)
+ [Ler dados de um índice secundário global](#GSI.Reading)
+ [Sincronização de dados entre tabelas e índices secundários globais](#GSI.Writes)
+ [Classes de tabela com índice secundário global](#GSI.tableclasses)
+ [Considerações sobre throughput provisionado para índices secundários globais](#GSI.ThroughputConsiderations)
+ [Considerações sobre armazenamento para índices secundários globais](#GSI.StorageConsiderations)
+ [Padrões de design](GSI.DesignPatterns.md)
+ [Gerenciar índices secundários globais no DynamoDB](GSI.OnlineOps.md)
+ [Detectar e corrigir violações de chave de índice no DynamoDB](GSI.OnlineOps.ViolationDetection.md)
+ [Como trabalhar com índices secundários globais: Java](GSIJavaDocumentAPI.md)
+ [Como trabalhar com índices secundários globais: .NET](GSILowLevelDotNet.md)
+ [Trabalhar com índices secundários globais no DynamoDB usando a AWS CLI](GCICli.md)

## Cenário: Uso de um índice secundário global
<a name="GSI.scenario"></a>

Para ilustrar, considere uma tabela chamada `GameScores` que controla os usuários e os placares de um aplicativo de jogo móvel. Cada item em `GameScores` é identificado por uma chave de partição (`UserId`) e por uma chave de classificação (`GameTitle`). O diagrama a seguir mostra como os itens da tabela seriam organizados. (Nem todos os atributos são mostrados.)

![\[A tabela GameScores que contém uma lista de ID de usuários, títulos, pontuações, datas e vitórias/derrotas.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/GSI_01.png)


Agora, vamos supor que você quisesse gravar um aplicativo de placar para exibir as pontuações máximas de cada jogo. Uma consulta que especificasse os atributos chave (`UserId` e `GameTitle`) seria muito eficaz. No entanto, se o aplicativo precisasse recuperar dados de `GameScores` com base no `GameTitle` apenas, ele precisaria usar uma operação `Scan`. À medida que mais itens são adicionados à tabela, as verificações de todos os dados se tornam lentas e ineficientes. Isso dificulta responder a questões como as seguintes:
+ Qual é a pontuação máxima já registrada no jogo Meteor Blasters?
+ Qual usuário tinha a maior pontuação no Galaxy Invaders?
+ Qual era a maior proporção de vitórias versus derrotas?

Para acelerar as consultas em atributos que não são chave, você pode criar um índice secundário global. Um índice secundário global contém uma seleção de atributos da tabela-base, mas eles são organizados por uma chave primária que é diferente daquela da região da tabela. A chave do índice não precisa ter nenhum dos atributos de chaves da tabela. Ela não precisa nem ter o mesmo esquema de chaves que a tabela.

Por exemplo, você poderia criar um índice secundário global chamado `GameTitleIndex` com uma chave de partição `GameTitle` e uma chave de classificação `TopScore`. Os atributos de chave primária da tabela base são sempre projetados em um índice, portanto, o atributo `UserId` também está presente. O diagrama a seguir mostra qual é a aparência do índice `GameTitleIndex`.

![\[A tabela GameTitleIndex que contém uma lista de títulos, pontuações e IDs de usuários.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/GSI_02.png)


Agora você pode consultar `GameTitleIndex` e obter as pontuações do jogo Meteor Blasters com facilidade. Os resultados são ordenados por valores de chave de classificação, `TopScore`. Se você definir o parâmetro `ScanIndexForward` como falso, os resultados serão retornados em ordem decrescente, de modo que a maior pontuação é retornada primeiro.

Cada índice secundário global deve ter uma chave de partição e pode ter uma chave de classificação opcional. O esquema da chave de índice pode ser diferente do esquema da tabela base. Você poderia ter uma tabela com uma chave primária simples (chave de partição) e criar um índice secundário global com uma chave primária composta (chave de partição e chave de classificação), ou vice versa. Os atributos de chaves do índice podem consistir em quaisquer atributos de nível superior, `String`, `Number` ou `Binary` da tabela base. Outros tipos escalares, tipos de documento e tipos de conjunto não são permitidos.

Você pode projetar outros atributos da tabela-base para o índice, se quisesse. Quando você consultar o índice, o DynamoDB poderá recuperar esses atributos projetados com eficiência. No entanto, as consultas do índice secundário global buscam atributos da tabela-base. Por exemplo, se você consultar `GameTitleIndex` conforme mostrado no diagrama anterior, a consulta poderá não acessar nenhum atributo que não seja de chave além de `TopScore` (embora os atributos de chave `GameTitle` e `UserId` sejam projetados automaticamente).

Em uma tabela do DynamoDB, cada valor de chave deve ser exclusivo. No entanto, os valores de chave em um índice secundário global não precisam ser exclusivos. Para ilustrar, suponhamos que um jogo chamado Comet Quest seja muito difícil. Há vários novos usuários tentando obter uma pontuação acima de zero, mas não conseguem. Veja a seguir alguns dos dados que podem representar isso.


****  

| UserId | GameTitle | TopScore | 
| --- | --- | --- | 
| 123 | Comet Quest | 0 | 
| 201 | Comet Quest | 0 | 
| 301 | Comet Quest | 0 | 

Quando esses dados são adicionados à tabela `GameScores`, o DynamoDB os propaga para o `GameTitleIndex`. Se consultarmos o índice usando Comet Quest para `GameTitle` e 0 para `TopScore`, os seguintes dados serão retornados.

![\[A tabela que contém uma lista de títulos, pontuações superiores e IDs de usuários.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/GSI_05.png)


Apenas os itens com os valores de chaves especificados aparecem na resposta. Nesse conjunto de dados, os itens não estão em nenhuma ordem específica. 

Um índice secundário global controla apenas os itens de dados em que seus atributos de chave realmente existem. Por exemplo, suponha que você tenha adicionado um novo item à tabela `GameScores`, mas forneceu somente os atributos de chave primária necessários.


****  

| UserId | GameTitle | 
| --- | --- | 
| 400 | Comet Quest | 

Como você não especificou o atributo `TopScore`, o DynamoDB não propagará esse item para `GameTitleIndex`. Portanto, se você tivesse consultado `GameScores` para obter todos os itens do Comet Quest, obteria os quatro itens a seguir.

![\[A tabela que contém uma lista de 4 títulos, pontuações superiores e IDs de usuários.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/GSI_04.png)


Uma consulta semelhante em `GameTitleIndex` ainda retornaria três itens, em vez de quatro. Isso acontece porque o item com `TopScore` inexistente não é propagado para o índice.

![\[A tabela que contém uma lista de 3 títulos, pontuações superiores e IDs de usuários.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/GSI_05.png)


## Projeções de atributo
<a name="GSI.Projections"></a>

Uma *projeção* é o conjunto de atributos que é copiado de uma tabela para um índice secundário. A chave de partição e a chave de classificação da tabela são sempre projetadas no índice; você pode projetar outros atributos para suportar os requisitos de consulta da sua aplicação. Quando você consulta um índice, o Amazon DynamoDB pode acessar quaisquer atributos na projeção como se estivessem em uma tabela própria.

Quando você cria um índice secundário, é necessário especificar os atributos que serão projetados no índice. O DynamoDB proporciona três opções diferentes para fazer isso:
+ *KEYS\$1ONLY*: cada item do índice consiste apenas nos valores de chaves de partição e nas chaves de classificação da tabela, além dos valores de chaves do índice. A opção `KEYS_ONLY` resulta no menor índice secundário possível.
+ *INCLUDE*: além dos atributos descritos em `KEYS_ONLY`, o índice secundário incluirá outros atributos não chave que você especificar.
+ *ALL*: o índice secundário inclui todos os atributos da tabela de origem. Como todos os dados da tabela são duplicados no índice, uma projeção `ALL` resulta no maior índice secundário possível.

No diagrama anterior, `GameTitleIndex` tem apenas um atributo projetado: `UserId` Portanto, embora um aplicativo possa determinar eficientemente o `UserId` dos melhores marcadores para cada jogo usando `GameTitle` e `TopScore` nas consultas, ele não pode determinar com eficiência a maior proporção de vitórias versus derrotas dos maiores marcadores. Para fazer isso, a aplicação teria que realizar uma consulta adicional na tabela base para buscar os ganhos e perdas de cada um dos maiores artilheiros. A maneira mais eficiente de oferecer suporte a consultas nesses dados seria projetar esses atributos da tabela-base no índice secundário global, conforme mostrado neste diagrama. 

![\[Descrição da projeção de atributos não essenciais em um GSI para oferecer suporte a consultas eficientes.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/GSI_06.png)


Como os atributos não são de chave `Wins` e `Losses` são projetados no índice, um aplicativo pode determinar a proporção de vitórias versus derrotas de qualquer jogo ou de qualquer combinação de jogo e ID do usuário.

Ao escolher os atributos para projetar em um índice secundário global, você deve considerar a desvantagem entre os custos de throughput provisionado e os custos de armazenamento:
+ Se você precisar acessar apenas alguns atributos com a latência mais baixa possível, considere projetar apenas os atributos em um índice secundário global. Quanto menor o índice, menores serão os custos de armazenamento e de gravação.
+ Se sua aplicação acessar frequentemente alguns atributos não chave, considere projetar esses atributos em um índice secundário global. Os custos adicionais de armazenamento do índice secundário global compensarão o custo de executar verificações de tabelas frequentes.
+ Se precisar acessar a maioria dos atributos não chave com frequência, você poderá projetar esses atributos, inclusive a tabela-base inteira, em um índice secundário global. Isso dá flexibilidade máxima a você. No entanto, o custo do armazenamento aumentará ou até dobrará.
+ Se o aplicativo precisar consultar uma tabela com pouca frequência, mas precisar executar muitas gravações ou atualizações nos dados da tabela, considere projetar `KEYS_ONLY`. O índice secundário global seria de tamanho mínimo, mas ainda estaria disponível quando necessário para a atividade de consulta. 

## Esquema de chave de vários atributos
<a name="GSI.MultiAttributeKeys"></a>

Os índices secundários globais são compatíveis com chaves de vários atributos, permitindo que você componha chaves de partição e chaves de classificação com base em vários atributos. Com chaves de vários atributos, você pode criar uma chave de partição com até quatro atributos e uma chave de classificação com até quatro atributos, totalizando até oito atributos por esquema de chave.

As chaves de vários atributos simplificam seu modelo de dados, eliminando a necessidade de concatenar manualmente os atributos em chaves sintéticas. Em vez de criar strings compostas, como `TOURNAMENT#WINTER2024#REGION#NA-EAST`, você pode usar diretamente os atributos naturais do seu modelo de domínio. O DynamoDB processa a lógica da chave composta automaticamente, unindo vários atributos da chave de partição para distribuição de dados e mantendo a ordem de classificação hierárquica em vários atributos da chave de classificação.

Por exemplo, considere um sistema de torneios de jogos em que você deseja organizar partidas por torneio e região. Com chaves de vários atributos, você pode definir sua chave de partição como dois atributos separados: `tournamentId` e `region`. Da mesma forma, você pode definir sua chave de classificação usando vários atributos, como `round`, `bracket` e `matchId`, para criar uma hierarquia natural. Essa abordagem mantém seus dados tipados e seu código limpo, sem manipulação nem análise de strings.

Quando você consulta um índice secundário global com chaves de vários atributos, deve especificar todos os atributos da chave de partição usando condições de igualdade. Em relação a atributos de chave de classificação, é possível consultá-los da esquerda para a direita na ordem em que estão definidos no esquema de chaves. Isso significa que você pode consultar o primeiro atributo da chave de classificação sozinho, os dois primeiros atributos juntos ou todos os atributos juntos, mas não pode ignorar os atributos no meio. Condições de desigualdade, como `>`, `<`, `BETWEEN` ou `begins_with()`, devem ser a última condição em sua consulta.

As chaves de vários atributos funcionam particularmente bem quando você cria índices secundários globais em tabelas existentes. Você pode usar atributos que já existem na sua tabela sem precisar preencher chaves sintéticas em todos os seus dados. Isso facilita a inclusão de novos padrões de consulta à sua aplicação criando índices que reorganizam seus dados usando diferentes combinações de atributos.

Cada atributo em uma chave de vários atributos pode ter seu próprio tipo de dados: `String` (S), `Number` (N) ou `Binary` (B). Quando você escolhe os tipos de dados, pense que os atributos `Number` são classificados numericamente sem exigir preenchimento zero, enquanto os atributos `String` são classificados de modo lexicográfico. Por exemplo, se você usar um tipo `Number` para um atributo de pontuação, os valores 5, 50, 500 e 1000 serão classificados em ordem numérica natural. Os mesmos valores, se fossem do tipo `String`, seriam ordenados como “1000”, “5”, “50”, “500”, a menos que você os preenchesse com zeros à esquerda.

Ao criar chaves de vários atributos, ordene seus atributos do mais geral para o mais específico. Para chaves de partição, combine atributos que são sempre consultados juntos e que oferecem uma boa distribuição de dados. Para chaves de classificação, coloque os atributos frequentemente consultados em primeiro lugar na hierarquia para maximizar a flexibilidade da consulta. Essa ordenação permite que você consulte em qualquer nível de granularidade que corresponda aos seus padrões de acesso.

Consulte exemplos de implementação em [Chaves de vários atributos](GSI.DesignPattern.MultiAttributeKeys.md).

## Ler dados de um índice secundário global
<a name="GSI.Reading"></a>

Você pode recuperar itens de um índice secundário global usando as operações `Query` e `Scan`. As operações `GetItem` e `BatchGetItem` não podem ser usadas em um índice secundário global.

### Como consultar um índice secundário global
<a name="GSI.Querying"></a>

Você pode usar a operação `Query` para acessar um ou mais itens em um índice secundário global. A consulta deve especificar o nome da tabela-base e o nome do índice que você deseja usar, os atributos a serem retornados nos resultados de consulta e quaisquer condições que você deseja aplicar. O DynamoDB pode retornar os resultados em ordem crescente ou decrescente.

Considere os seguintes dados retornados de uma `Query` que solicita dados de jogos para um aplicativo de placar.

```
{
    "TableName": "GameScores",
    "IndexName": "GameTitleIndex",
    "KeyConditionExpression": "GameTitle = :v_title",
    "ExpressionAttributeValues": {
        ":v_title": {"S": "Meteor Blasters"}
    },
    "ProjectionExpression": "UserId, TopScore",
    "ScanIndexForward": false
}
```

Nesta consulta:
+ O DynamoDB acessa *GameTitleIndex* usando a chave de partição *GameTitle* para localizar os itens de índice do Meteor Blasters. Todos os itens do índice com essa chave são armazenados lado a lado para rápida recuperação.
+ Nesse jogo, o DynamoDB usa o índice para acessar todos os IDs de usuário e as pontuações máximas.
+ Os resultados são retornados, classificados em ordem decrescente, pois o parâmetro `ScanIndexForward` está definido como falso.

### Como verificar um índice secundário global
<a name="GSI.Scanning"></a>

Você pode usar a operação `Scan` para recuperar todos os dados de um índice secundário global. Você deve fornecer o nome da tabela-base e o nome de índice na solicitação. Com uma operação `Scan`, o DynamoDB lê todos os dados do índice e os retorna para a aplicação. Você também pode solicitar que apenas alguns dos dados sejam retornados, e que os dados restantes sejam descartados. Para fazer isso, use o parâmetro `FilterExpression` da operação `Scan`. Para obter mais informações, consulte [Expressões de filtro para verificação](Scan.md#Scan.FilterExpression).

## Sincronização de dados entre tabelas e índices secundários globais
<a name="GSI.Writes"></a>

O DynamoDB sincroniza automaticamente cada índice secundário global com sua tabela-base. Quando uma aplicação grava ou exclui itens em uma tabela, quaisquer índices secundários globais nessa tabela são atualizados de forma assíncrona usando um modelo final consistente. Os aplicativos nunca gravam diretamente em um índice. No entanto, é importante compreender as implicações de como o DynamoDB mantém esses índices.

 Índices secundários globais herdam o modo de capacidade leitura/gravação da tabela base. Para obter mais informações, consulte [Considerações ao alternar os modos de capacidade no DynamoDB](bp-switching-capacity-modes.md). 

Ao criar um índice secundário global, você especifica um ou mais atributos de chave de índice e seus tipos de dados. Isso significa que sempre que você grava um item na tabela-base, os tipos de dados desses atributos devem corresponder aos tipos de dados do esquema de chaves do índice. No caso de `GameTitleIndex`, a chave de partição `GameTitle` no índice é definida como um tipo de dados `String`. A chave de classificação `TopScore` no índice é do tipo `Number`. Se você tentar adicionar um item à tabela `GameScores` e especificar um tipo de dados diferente para `GameTitle` ou `TopScore`, o DynamoDB retornará uma `ValidationException` devido à inconsistência do tipo de dados.

Quando você insere ou exclui itens em uma tabela, os índices secundários globais dessa tabela são atualizados de uma forma eventualmente consistente. As alterações na tabela são propagadas para os índices secundários globais em uma fração de segundo, sob condições normais. No entanto, em alguns cenários improváveis de falha, podem ocorrer atrasos de propagação mais longos. Consequentemente, as aplicações precisam prever e lidar com situações em que uma consulta em um índice secundário global retorna resultados que não estão atualizados.

Se você gravar um item em uma tabela, não será necessário especificar os atributos para qualquer chave de classificação do índice secundário global. Usando `GameTitleIndex` como um exemplo, você não precisa especificar um valor para o atributo `TopScore` para gravar um novo item na tabela `GameScores`. Neste caso, o DynamoDB não grava todos os dados no índice deste item específico.

Os custos das atividades de gravação em uma tabela com muitos índices secundários serão mais altos do que em uma tabela com um número menor de índices. Para obter mais informações, consulte [Considerações sobre throughput provisionado para índices secundários globais](#GSI.ThroughputConsiderations).

## Classes de tabela com índice secundário global
<a name="GSI.tableclasses"></a>

Um índice secundário global sempre usará a mesma classe de tabela que sua tabela-base. Sempre que um novo índice secundário global for adicionado para uma tabela, o novo índice usará a mesma classe de tabela que sua tabela base. Quando a classe de tabela de uma tabela é atualizada, todos os índices secundários globais associados também são atualizados.

## Considerações sobre throughput provisionado para índices secundários globais
<a name="GSI.ThroughputConsiderations"></a>

Ao criar um índice secundário global em uma tabela de modo provisionado, você deve especificar unidades de capacidade de leitura e gravação para a workload esperada no índice. As configurações de throughput provisionado de um índice secundário global são separadas daquelas de sua tabela-base. Uma operação `Query` em um índice secundário global consome unidades de capacidade de leitura do índice, não da tabela-base. Quando você insere ou exclui itens em uma tabela, os índices secundários globais dessa tabela também são atualizados. Essas atualizações de índice consomem unidades de capacidade do índice, não da tabela base.

Por exemplo, se você usar a operação `Query` em um índice secundário global e exceder sua capacidade de leitura provisionada, sua solicitação será limitada. Se você executar atividades de gravação pesadas na tabela, mas um índice secundário global da tabela tiver capacidade de gravação insuficiente, a atividade de gravação na tabela será limitada.

**Importante**  
 Para evitar o controle de utilização potencial, a capacidade de gravação provisionada para um índice secundário global deve ser igual ou maior que a capacidade de gravação da tabela base, porque as novas atualizações gravarão na tabela base e no índice secundário global. 

Para visualizar as configurações de throughput provisionado de um índice secundário global, use a operação `DescribeTable`. Informações detalhadas sobre todos os índices secundários globais da tabela são retornados.

### Unidades de capacidade de leitura
<a name="GSI.ThroughputConsiderations.Reads"></a>

Os índices secundários globais oferecem suporte a leituras eventualmente consistentes, cada uma delas consome metade de uma unidade de capacidade de leitura. Isso significa que uma única consulta de índice secundário global pode recuperar até 2 × 4 KB = 8 KB por unidade de capacidade de leitura.

Para consultas de índice secundário global, o DynamoDB calcula a atividade de leitura provisionada da mesma forma que para consultas em tabelas. A única diferença é que o cálculo é baseado no tamanho das entradas de índice, em vez do tamanho do item na tabela-base. O número de unidades de capacidade de leitura é a soma de todos os tamanhos de atributos projetados em todos os itens retornados. O resultado é arredondado para o próximo limite de 4 KB. Para obter mais informações sobre como o DynamoDB calcula a utilização de throughput provisionado, consulte [Modo de capacidade provisionada do DynamoDB](provisioned-capacity-mode.md).

O tamanho máximo dos resultados retornados por uma operação `Query` é 1 MB. Isso inclui os tamanhos de todos os nomes e valores de atributos de todos os itens retornados.

Por exemplo, considere um índice secundário global em que cada item contém 2.000 bytes de dados. Agora vamos supor que você use a operação `Query` nesse índice e que `KeyConditionExpression` da consulta retorne oito itens. O tamanho total dos itens correspondentes é 2.000 bytes × 8 itens = 16.000 bytes. O resultado é arredondado para o próximo limite de 4 KB. Como as consultas do índice secundário global são finais consistentes, o custo total é 0,5 × (16 KB / 4 KB), ou 2 unidades de capacidade de leitura.

### Unidades de capacidade de gravação
<a name="GSI.ThroughputConsiderations.Writes"></a>

Quando um item é adicionado, atualizado ou excluído em uma tabela, e um índice secundário global é afetado por isso, o índice secundário global consome unidades de capacidade de gravação provisionadas para a operação. O custo total do throughput provisionado para uma gravação consiste na soma das unidades de capacidade de gravação consumidas pela gravação na tabela base e pela atualização dos índices secundários globais. Se uma gravação em uma tabela não exigir uma atualização do índice secundário global, nenhuma capacidade de gravação será consumida no índice.

Para que uma gravação de tabela seja bem-sucedida, as configurações do throughput provisionado e todos os seus índices secundários globais devem ter capacidade de gravação suficiente para acomodar a gravação. Caso contrário, a gravação na tabela será limitada. 

**Importante**  
Ao criar um índice secundário global (GSI), as operações de gravação na tabela base poderão sofrer controle de utilização se a atividade do GSI resultante das gravações na tabela base exceder a capacidade de gravação provisionada do GSI. Esse controle de utilização afeta todas as operações de gravação, desde o processo de indexação até a possível interrupção de suas workloads de produção. Para ter mais informações, consulte [Problemas de controle de utilização no Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TroubleshootingThrottling.html).

O custo de gravar um item em um índice secundário global depende de vários fatores:
+ Se você gravar um novo item na tabela que define um atributo indexado, ou atualizar um item existente para definir um atributo indexado indefinido anteriormente, uma operação de gravação é necessária para inserir o item no índice.
+ Se uma atualização na tabela alterar o valor de um atributo de chave indexado (de A para B), duas gravações serão necessárias, uma para excluir o item anterior do índice e outra gravação para inserir o novo item no índice.  
+ Se um item estava presente no índice, mas uma gravação na tabela fez com que o atributo indexado fosse excluído, uma gravação é necessária para excluir a projeção do item antigo do índice.
+ Se um item não estiver presente no índice antes ou depois que o item é atualizado, não haverá custo de gravação adicionais para o índice.
+ Se uma atualização na tabela alterar somente o valor dos atributos projetados no esquema de chaves do índice, mas não alterar o valores de qualquer atributo de chave indexado, uma gravação será necessária para atualizar os valores dos atributos projetados no índice.

Todos esses fatores supõem que o tamanho de cada item no índice seja menor ou igual ao tamanho de item de 1 KB para calcular unidades de capacidade de gravação. Entradas de índice maiores exigirão unidades adicionais de capacidade de gravação. Você pode minimizar os custos de gravação, considerando quais atributos suas consultas precisarão retornar e projetar apenas esses atributos no índice.

## Considerações sobre armazenamento para índices secundários globais
<a name="GSI.StorageConsiderations"></a>

Quando uma aplicação grava um item em uma tabela, o DynamoDB copia automaticamente o subconjunto de atributos corretos para qualquer índice secundário global no qual esses atributos devem aparecer. Sua conta da AWS é cobrada pelo armazenamento do item na tabela-base e também pelo armazenamento de atributos em qualquer índice secundário global dessa tabela.

A quantidade de espaço usada por um item do índice é a soma do seguinte:
+ O tamanho em bytes da chave primária da tabela-base (chave de partição e chave de classificação)
+ O tamanho em bytes do atributo de chave do índice
+ O tamanho em bytes dos atributos projetados (se houver)
+ 100 bytes de sobrecarga por item de índice

Para estimar os requisitos de armazenamento de um índice secundário global, você pode estimar o tamanho médio de um item no índice e multiplicar pelo número de itens da tabela-base que têm os atributos de chave do índice secundário global.

Se uma tabela contiver um item em que determinado atributo não esteja definido, mas esteja configurado como uma chave de partição ou chave de classificação do índice, o DynamoDB não gravará nenhum dado desse item no índice.

# Padrões de design
<a name="GSI.DesignPatterns"></a>

Os padrões de design fornecem soluções comprovadas para desafios comuns quando você trabalha com índices secundários globais. Esses padrões ajudam você a criar aplicações eficientes e escaláveis, mostrando como estruturar seus índices para casos de uso específicos.

Cada padrão inclui um guia de implementação completo com exemplos de código, práticas recomendadas e casos de uso reais para ajudar você a aplicar o padrão em suas próprias aplicações.

**Topics**
+ [Chaves de vários atributos](GSI.DesignPattern.MultiAttributeKeys.md)

# Padrão de chaves de vários atributos
<a name="GSI.DesignPattern.MultiAttributeKeys"></a>

## Visão geral
<a name="GSI.DesignPattern.MultiAttributeKeys.Overview"></a>

As chaves de vários atributos permitem criar partições de Índice Secundário Global (GSI) e chaves de classificação compostas por até quatro atributos cada. Isso reduz o código do lado do cliente e facilita a modelagem inicial dos dados e a adição posterior de novos padrões de acesso.

Pense em um cenário comum: para criar um GSI que consulte itens por vários atributos hierárquicos, você tradicionalmente precisaria criar chaves sintéticas concatenando valores. Por exemplo, em uma aplicação de jogos, para consultar partidas de torneios por torneio, região e rodada, você pode criar uma chave de partição de GSI sintética, como TOURNAMENT\$1WINTER2024\$1REGION\$1NA-EAST, e uma chave de classificação sintética, como ROUND\$1SEMIFINALS\$1BRACKET\$1UPPER. Essa abordagem funciona, mas requer concatenação de strings ao gravar dados, analisar durante a leitura e preencher chaves sintéticas em todos os itens existentes se você estiver adicionando o GSI a uma tabela existente. Isso torna o código mais confuso e desafiador para manter a segurança de tipos em componentes de chave individuais.

As chaves de vários atributos resolvem esse problema para GSIs. Você define sua chave de partição de GSI usando vários atributos existentes, como tournamentId e region. O DynamoDB processa a lógica da chave composta automaticamente, juntando-as para distribuição de dados. Você grava itens usando atributos naturais do seu modelo de domínio e o GSI os indexa automaticamente. Sem concatenação, sem análise, sem preenchimento. Seu código permanece limpo, seus dados permanecem tipados e suas consultas permanecem simples. Essa abordagem é particularmente útil quando você tem dados hierárquicos com agrupamentos de atributos naturais (como torneio → região → rodada ou organização → departamento → equipe).

## Aplicação de exemplo
<a name="GSI.DesignPattern.MultiAttributeKeys.ApplicationExample"></a>

Este guia explica a criação de um sistema de rastreamento de partidas de torneios para uma plataforma de esportes eletrônicos. A plataforma precisa consultar partidas de forma eficiente em várias dimensões: por torneio e região para gerenciamento de chaves, por jogador para o histórico de partidas e por data para agendamento.

## Modelo de dados
<a name="GSI.DesignPattern.MultiAttributeKeys.DataModel"></a>

Neste passo a passo, o sistema de rastreamento de partidas do torneio comporta três padrões de acesso primários, cada um exigindo uma estrutura de chave diferente:

**Padrão de acesso 1:** procure uma correspondência específica por seu ID exclusivo.
+ **Solução:** tabela base com `matchId` como chave de partição.

**Padrão de acesso 2:** consulte todas as partidas de um torneio e região específicos, opcionalmente filtrando por rodada, chave ou partida.
+ **Solução:** índice secundário global com chave de partição de vários atributos (`tournamentId` \$1 `region`) e chave de classificação de vários atributos (`round` \$1 `bracket` \$1 `matchId`).
+ **Consultas de exemplo:** “Todas as partidas WINTER2024 na região NA-EAST” ou “Todas as partidas de SEMIFINALS na chave UPPER de WINTER2024/NA-EAST”.

**Padrão de acesso 3:** consulte o histórico de partidas de um jogador, opcionalmente filtrando por intervalo de datas ou rodada do torneio.
+ **Solução:** índice secundário global com uma chave de partição (`player1Id`) e uma chave de classificação de vários atributos (`matchDate` \$1 `round`).
+ **Consultas de exemplo:** “Todas as partidas do jogador 101" ou “Partidas do jogador 101 em janeiro de 2024".

A principal diferença entre as abordagens tradicional e de vários atributos fica clara ao examinar a estrutura do item:

**Abordagem tradicional do Índice Secundário Global (chaves concatenadas):**

```
// 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
};
```

**Abordagem de Índice Secundário Global de vários atributos (chaves nativas):**

```
// 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
};
```

Com chaves de vários atributos, você grava itens uma vez com atributos de domínio naturais. O DynamoDB os indexa automaticamente em vários GSIs sem exigir chaves concatenadas sintéticas.

**Esquema da tabela base:**
+ Chave de partição: `matchId` (1 atributo)

**Esquema de Índice Secundário Global (TournamentRegionIndex com chaves de vários atributos):**
+ Chave de partição: `tournamentId`, `region` (2 atributos)
+ Chave de classificação: `round`, `bracket`, `matchId` (3 atributos)

**Esquema de Índice Secundário Global (PlayerMatchHistoryIndex com chaves de vários atributos):**
+ Chave de partição: `player1Id` (1 atributo)
+ Chave de classificação: `matchDate`, `round` (2 atributos)

### Tabela base: TournamentMatches
<a name="GSI.DesignPattern.MultiAttributeKeys.BaseTable"></a>


| matchId (PK) | tournamentId | região | round | bracket | player1Id | player2Id | matchDate | winner | pontuação | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| match-001 | WINTER2024 | NA-EAST | FINALS | CHAMPIONSHIP | 101 | 103 | 2024-01-20 | 101 | 3-1 | 
| match-002 | WINTER2024 | NA-EAST | SEMIFINALS | UPPER | 101 | 105 | 2024-01-18 | 101 | 3-2 | 
| match-003 | WINTER2024 | NA-EAST | SEMIFINALS | UPPER | 103 | 107 | 2024-01-18 | 103 | 3-0 | 
| match-004 | WINTER2024 | NA-EAST | QUARTERFINALS | UPPER | 101 | 109 | 2024-01-15 | 101 | 3-1 | 
| match-005 | WINTER2024 | NA-WEST | FINALS | CHAMPIONSHIP | 102 | 104 | 2024-01-20 | 102 | 3-2 | 
| match-006 | WINTER2024 | NA-WEST | SEMIFINALS | UPPER | 102 | 106 | 2024-01-18 | 102 | 3-1 | 
| match-007 | SPRING2024 | NA-EAST | QUARTERFINALS | UPPER | 101 | 108 | 2024-03-15 | 101 | 3-0 | 
| match-008 | SPRING2024 | NA-EAST | QUARTERFINALS | LOWER | 103 | 110 | 2024-03-15 | 103 | 3-2 | 

### GSI: TournamentRegionIndex (chaves de vários atributos)
<a name="GSI.DesignPattern.MultiAttributeKeys.TournamentRegionIndexTable"></a>


| tournamentId (PK) | region (PK) | round (SK) | bracket (SK) | matchId (SK) | player1Id | player2Id | matchDate | winner | pontuação | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| WINTER2024 | NA-EAST | FINALS | CHAMPIONSHIP | match-001 | 101 | 103 | 2024-01-20 | 101 | 3-1 | 
| WINTER2024 | NA-EAST | QUARTERFINALS | UPPER | match-004 | 101 | 109 | 2024-01-15 | 101 | 3-1 | 
| WINTER2024 | NA-EAST | SEMIFINALS | UPPER | match-002 | 101 | 105 | 2024-01-18 | 101 | 3-2 | 
| WINTER2024 | NA-EAST | SEMIFINALS | UPPER | match-003 | 103 | 107 | 2024-01-18 | 103 | 3-0 | 
| WINTER2024 | NA-WEST | FINALS | CHAMPIONSHIP | match-005 | 102 | 104 | 2024-01-20 | 102 | 3-2 | 
| WINTER2024 | NA-WEST | SEMIFINALS | UPPER | match-006 | 102 | 106 | 2024-01-18 | 102 | 3-1 | 
| SPRING2024 | NA-EAST | QUARTERFINALS | LOWER | match-008 | 103 | 110 | 2024-03-15 | 103 | 3-2 | 
| SPRING2024 | NA-EAST | QUARTERFINALS | UPPER | match-007 | 101 | 108 | 2024-03-15 | 101 | 3-0 | 

### GSI: PlayerMatchHistoryIndex (chaves de vários atributos)
<a name="GSI.DesignPattern.MultiAttributeKeys.PlayerMatchHistoryIndexTable"></a>


| player1Id (PK) | matchDate (SK) | round (SK) | tournamentId | região | bracket | matchId | player2Id | winner | pontuação | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| 101 | 2024-01-15 | QUARTERFINALS | WINTER2024 | NA-EAST | UPPER | match-004 | 109 | 101 | 3-1 | 
| 101 | 2024-01-18 | SEMIFINALS | WINTER2024 | NA-EAST | UPPER | match-002 | 105 | 101 | 3-2 | 
| 101 | 2024-01-20 | FINALS | WINTER2024 | NA-EAST | CHAMPIONSHIP | match-001 | 103 | 101 | 3-1 | 
| 101 | 2024-03-15 | QUARTERFINALS | SPRING2024 | NA-EAST | UPPER | match-007 | 108 | 101 | 3-0 | 
| 102 | 2024-01-18 | SEMIFINALS | WINTER2024 | NA-WEST | UPPER | match-006 | 106 | 102 | 3-1 | 
| 102 | 2024-01-20 | FINALS | WINTER2024 | NA-WEST | CHAMPIONSHIP | match-005 | 104 | 102 | 3-2 | 
| 103 | 2024-01-18 | SEMIFINALS | WINTER2024 | NA-EAST | UPPER | match-003 | 107 | 103 | 3-0 | 
| 103 | 2024-03-15 | QUARTERFINALS | SPRING2024 | NA-EAST | LOWER | match-008 | 110 | 103 | 3-2 | 

## Pré-requisitos
<a name="GSI.DesignPattern.MultiAttributeKeys.Prerequisites"></a>

Antes de começar, verifique se você tem:

### Conta e permissões
<a name="GSI.DesignPattern.MultiAttributeKeys.Prerequisites.AWSAccount"></a>
+ Uma conta da AWS ativa ([crie uma aqui](https://aws.amazon.com/free/), se necessário)
+ Permissões do IAM para operações do DynamoDB:
  + `dynamodb:CreateTable`
  + `dynamodb:DeleteTable`
  + `dynamodb:DescribeTable`
  + `dynamodb:PutItem`
  + `dynamodb:Query`
  + `dynamodb:BatchWriteItem`

**nota**  
**Nota de segurança:** para uso em produção, crie uma política do IAM personalizada com apenas as permissões necessárias. Para este tutorial, você pode usar a política gerenciada pela AWS `AmazonDynamoDBFullAccessV2`.

### Ambiente de desenvolvimento
<a name="GSI.DesignPattern.MultiAttributeKeys.Prerequisites.DevEnvironment"></a>
+ Node.js instalado em sua máquina
+ Credenciais da AWS configuradas usando um dos seguintes métodos:

**Opção 1: AWS CLI**

```
aws configure
```

**Opção 2: Variáveis de ambiente**

```
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
```

### Instalar os pacotes obrigatórios
<a name="GSI.DesignPattern.MultiAttributeKeys.Prerequisites.InstallPackages"></a>

```
npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
```

## Implementação
<a name="GSI.DesignPattern.MultiAttributeKeys.Implementation"></a>

### Etapa 1: criar tabela com GSIs usando chaves de vários atributos
<a name="GSI.DesignPattern.MultiAttributeKeys.CreateTable"></a>

Crie uma tabela com uma estrutura de chave básica simples e GSIs que usam chaves de vários atributos.

#### Exemplo de código
<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");
```

**Principais decisões de design:**

**Tabela base:** a tabela base usa uma chave de partição `matchId` simples para pesquisas diretas de correspondência, mantendo a estrutura da tabela base simples, enquanto os GSIs fornecem padrões de consulta complexos.

**Índice Secundário Global TournamentRegionIndex:** o Índice Secundário Global `TournamentRegionIndex` usa `tournamentId` \$1 `region` como uma chave de partição de vários atributos, criando um isolamento da região do torneio em que os dados são distribuídos pelo hash de ambos os atributos combinados, permitindo consultas eficientes dentro de um contexto específico da região do torneio. A chave de classificação de vários atributos (`round` \$1 `bracket` \$1`matchId`) fornece classificação hierárquica que comporta consultas em qualquer nível da hierarquia com ordenação natural do geral (redondo) ao específico (ID de correspondência).

**Índice secundário global PlayerMatchHistoryIndex:** o Índice Secundário Global `PlayerMatchHistoryIndex` reorganiza os dados por jogador usando `player1Id` como chave de partição, permitindo consultas entre torneios para um jogador específico. A chave de classificação de vários atributos (`matchDate` \$1 `round`) fornece ordem cronológica com a capacidade de filtrar por intervalos de datas ou rodadas específicas do torneio.

### Etapa 2: inserir dados com atributos nativos
<a name="GSI.DesignPattern.MultiAttributeKeys.InsertData"></a>

Adicione dados da partida do torneio usando atributos naturais. O GSI indexará automaticamente esses atributos sem exigir chaves sintéticas.

#### Exemplo de código
<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");
```

**Estrutura de dados explicada:**

**Uso de atributos naturais:** cada atributo representa um conceito real de torneio sem necessidade de concatenação ou análise de strings, fornecendo mapeamento direto para o modelo de domínio.

**Indexação automática do Índice Secundário Global:** os GSIs indexam itens automaticamente usando os atributos existentes (`tournamentId`, `region`, `round`, `bracket`, `matchId` para TournamentRegionIndex e `player1Id`, `matchDate`, `round` para PlayerMatchHistoryIndex) sem exigir chaves concatenadas sintéticas.

**Sem necessidade de preenchimento:** quando você adiciona um novo Índice Secundário Global com chaves de vários atributos a uma tabela existente, o DynamoDB indexa automaticamente todos os itens existentes usando seus atributos naturais, sem a necessidade de atualizar os itens com chaves sintéticas.

### Etapa 3: consultar o Índice Secundário Global TournamentRegionIndex com todos os atributos da chave de partição
<a name="GSI.DesignPattern.MultiAttributeKeys.QueryAllPartitionKeys"></a>

Este exemplo consulta o Índice Secundário Global TournamentRegionIndex, que tem uma chave de partição de vários atributos (`tournamentId` \$1 `region`). Todos os atributos da chave de partição devem ser especificados com condições de igualdade nas consultas, ou seja, você não pode fazer consultas com apenas `tournamentId` sozinho ou usar operadores de desigualdade nos atributos da chave de partição.

#### Exemplo de código
<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`);
});
```

**Saída esperada:**

```
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
```

**Consultas inválidas:**

```
// Missing region attribute
KeyConditionExpression: 'tournamentId = :tournament'

// Using inequality on partition key attribute
KeyConditionExpression: 'tournamentId = :tournament AND #region > :region'
```

**Performance:** as chaves de partição de vários atributos são combinadas por meio de uma função hash, fornecendo a mesma performance de pesquisa O(1) como chaves de atributo único.

### Etapa 4: consultar as chaves de classificação do Índice Secundário Global da esquerda para a direita
<a name="GSI.DesignPattern.MultiAttributeKeys.QuerySortKeysLeftToRight"></a>

Os atributos da chave de classificação devem ser consultados da esquerda para a direita na ordem em que estão definidos no Índice Secundário Global. Este exemplo demonstra a consulta do TournamentRegionIndex em diferentes níveis hierárquicos: filtrando por apenas `round`, por `round` \$1 `bracket` ou por todos os três atributos da chave de classificação. Você não pode ignorar atributos no meio, por exemplo, você não pode consultar por `round` e `matchId` e ignorar `bracket`.

#### Exemplo de código
<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`);
}
```

**Saída esperada:**

```
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
```

**Regras de consulta da esquerda para a direita:** você deve consultar os atributos na ordem da esquerda para a direita, sem ignorar nenhum.

**Padrões válidos:**
+ Somente o primeiro atributo: `round = 'SEMIFINALS'`
+ Primeiros dois atributos: `round = 'SEMIFINALS' AND bracket = 'UPPER'`
+ Todos os três atributos: `round = 'SEMIFINALS' AND bracket = 'UPPER' AND matchId = 'match-002'`

**Padrões inválidos:**
+ Ignorando o primeiro atributo: `bracket = 'UPPER'` (ignora uma rodada)
+ Consulta fora de ordem: `matchId = 'match-002' AND round = 'SEMIFINALS'`
+ Deixando lacunas: `round = 'SEMIFINALS' AND matchId = 'match-002'` (ignora a chave)

**nota**  
**Dica de design:** ordene os atributos da chave de classificação do mais geral para o mais específico para maximizar a flexibilidade da consulta.

### Etapa 5: usar condições de desigualdade nas chaves de classificação do Índice Secundário Global
<a name="GSI.DesignPattern.MultiAttributeKeys.InequalityConditions"></a>

Condições de desigualdade devem ser a última condição em sua consulta. Este exemplo demonstra o uso de operadores de comparação (`>=`, `BETWEEN`) e correspondência de prefixo (`begins_with()`) nos atributos da chave de classificação. Depois de usar um operador de desigualdade, você não pode adicionar nenhuma condição adicional de chave de classificação depois dele, ou seja, a desigualdade deve ser a condição final em sua expressão de condição de chave.

#### Exemplo de código
<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`);
}
```

**Regras do operador de desigualdade:** você pode usar operadores de comparação (`>`, `>=`, `<`, `<=`) `BETWEEN` para consultas de intervalo e `begins_with()` para correspondência de prefixos. A desigualdade deve ser a última condição em sua consulta.

**Padrões válidos:**
+ Condições de igualdade seguidas de desigualdade: `round = 'SEMIFINALS' AND bracket = 'UPPER' AND matchId > 'match-001'`
+ Desigualdade no primeiro atributo: `round BETWEEN 'QUARTERFINALS' AND 'SEMIFINALS'`
+ Correspondência de prefixo como condição final: `round = 'SEMIFINALS' AND begins_with(bracket, 'U')`

**Padrões inválidos:**
+ Adicionando condições após uma desigualdade: `round > 'QUARTERFINALS' AND bracket = 'UPPER'`
+ Usando várias desigualdades: `round > 'QUARTERFINALS' AND bracket > 'L'`

**Importante**  
`begins_with()` é tratada como uma condição de desigualdade, portanto, nenhuma condição adicional de chave de classificação pode segui-la.

### Etapa 6: consultar o Índice Secundário Global PlayerMatchHistoryIndex com chaves de classificação vários atributos
<a name="GSI.DesignPattern.MultiAttributeKeys.QueryPlayerHistory"></a>

Este exemplo consulta o PlayerMatchHistoryIndex, que tem uma única chave de partição (`player1Id`) e uma chave de classificação de vários atributos (`matchDate` \$1 `round`). Isso permite a análise de vários torneios consultando todas as partidas de um jogador específico sem saber os IDs do torneio, enquanto a tabela base exigiria consultas separadas por combinação de torneio e região.

#### Exemplo de código
<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`);
```

## Variações de padrões
<a name="GSI.DesignPattern.MultiAttributeKeys.PatternVariations"></a>

### Dados de séries temporais com chaves de vários atributos
<a name="GSI.DesignPattern.MultiAttributeKeys.TimeSeries"></a>

Otimizar para consultas de séries temporais com atributos de tempo hierárquicos

#### Exemplo de código
<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
```

**Benefícios:** a hierarquia de tempo natural (ano → mês → dia → carimbo de data/hora) permite consultas eficientes em qualquer momento, granularidade, sem análise ou manipulação de datas. O Índice Secundário Global indexa automaticamente todas as leituras usando seus atributos de tempo natural.

### Pedidos de comércio eletrônico com chaves de vários atributos
<a name="GSI.DesignPattern.MultiAttributeKeys.ECommerce"></a>

Monitorar pedidos com várias dimensões

#### Exemplo de código
<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
```

### Dados de organizações hierárquicas
<a name="GSI.DesignPattern.MultiAttributeKeys.Hierarchical"></a>

Hierarquias organizacionais de modelos

#### Exemplo de código
<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
```

### Chaves esparsas de vários atributos
<a name="GSI.DesignPattern.MultiAttributeKeys.Sparse"></a>

Combinar chaves de vários atributos para criar um GSI esparso

#### Exemplo de código
<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 e multilocação
<a name="GSI.DesignPattern.MultiAttributeKeys.SaaS"></a>

Plataforma SaaS multilocatário com isolamento de clientes

#### Exemplo de código
<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'
    }
}));
```

**Benefícios:** consultas eficientes no contexto locatário-cliente e na organização natural dos dados.

### Transações financeiras
<a name="GSI.DesignPattern.MultiAttributeKeys.Financial"></a>

Sistema bancário monitorando transações de contas usando GSIs

#### Exemplo de código
<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'
    }
}));
```

## Exemplo completo
<a name="GSI.DesignPattern.MultiAttributeKeys.CompleteExample"></a>

O exemplo a seguir demonstra chaves de vários atributos, da configuração à limpeza:

### Exemplo de código
<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);
```

**Estrutura de código mínima**

### Exemplo de código
<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' }
```

## Recursos adicionais
<a name="GSI.DesignPattern.MultiAttributeKeys.AdditionalResources"></a>
+ [Práticas recomendadas do DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/best-practices.html)
+ [Trabalho com tabelas e dados](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithTables.html)
+ [Índices secundários globais](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html)
+ [Operações de consulta e verificação](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html)

# Gerenciar índices secundários globais no DynamoDB
<a name="GSI.OnlineOps"></a>

Esta seção descreve como criar, modificar e excluir índices secundários globais no Amazon DynamoDB.

**Topics**
+ [Criar uma tabela com índices secundários globais](#GSI.Creating)
+ [Descrever os índices secundários globais em uma tabela](#GSI.Describing)
+ [Adicionar um índice secundário global a uma tabela](#GSI.OnlineOps.Creating)
+ [Exclusão de um índice secundário global](#GSI.OnlineOps.Deleting)
+ [Modificar um índice secundário global durante a criação](#GSI.OnlineOps.Creating.Modify)

## Criar uma tabela com índices secundários globais
<a name="GSI.Creating"></a>

Para criar uma tabela com um ou mais índices secundários globais, use a operação `CreateTable` com o parâmetro `GlobalSecondaryIndexes`. Para obter a flexibilidade máxima de consultas, é possível criar até 20 índices secundários globais (cota padrão) por tabela. 

Você deve especificar um atributo que não atue como chave de partição do índice. Como opção, você pode especificar outro atributo para a chave de classificação do índice. Não é necessário que nenhum desses atributos de chave seja o mesmo que um atributo de chave na tabela. Por exemplo, na tabela *GameScores* (consulte [Como usar índices secundários globais no DynamoDB](GSI.md)), nem `TopScore` nem `TopScoreDateTime` são atributos chave. Você poderia criar um índice secundário global com uma chave de partição `TopScore` e uma chave de classificação `TopScoreDateTime`. Um índice desse tipo pode ser usado para determinar se há uma correlação entre pontuações altas e a hora do dia em que um jogo é jogado.

Cada atributo de chave de índice deve ser um escalar do tipo `String`, `Number` ou `Binary`. (Ele não pode ser um documento ou um conjunto.) Você pode projetar atributos de qualquer tipo de dados em um índice secundário global. Isso inclui escalares, documentos e conjuntos. Para obter uma lista completa de tipos de dados, consulte [Tipos de dados](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes).

Se estiver usando o modo provisionado, você deve fornecer configurações de `ProvisionedThroughput` para o índice, formadas por `ReadCapacityUnits` e `WriteCapacityUnits`. Essas configurações de throughput provisionado são distintas daquelas na tabela, mas se comportam de forma semelhante. Para obter mais informações, consulte [Considerações sobre throughput provisionado para índices secundários globais](GSI.md#GSI.ThroughputConsiderations).

 Índices secundários globais herdam o modo de capacidade leitura/gravação da tabela base. Para obter mais informações, consulte [Considerações ao alternar os modos de capacidade no DynamoDB](bp-switching-capacity-modes.md). 

**nota**  
 Ao criar um novo GSI, pode ser importante conferir se a escolha de chave de partição está gerando uma distribuição desigual ou estreita de dados ou tráfego nos valores de chave de partição do novo índice. Se isso ocorrer, você pode estar vendo operações de provisionamento e de gravação ocorrendo ao mesmo tempo e restringindo as gravações na tabela base. O serviço toma medidas para minimizar o potencial desse caso, mas não tem insights sobre o formato dos dados do cliente em relação à chave de partição de índice, à projeção escolhida ou à dispersão da chave primária do índice.  
Se você suspeitar que o novo índice secundário global tenha dados estreitos ou distorcidos ou distribuição de tráfego entre valores de chave de partição, considere o seguinte antes de adicionar novos índices a tabelas operacionalmente importantes.  
Talvez seja mais seguro adicionar o índice no momento em que a aplicação está gerando a menor quantidade de tráfego.
Considere habilitar o CloudWatch Contributor Insights em sua tabela e índices de base. Isso lhe proporcionará um valioso insight sobre sua distribuição de tráfego.
 Observe as métricas `WriteThrottleEvents`, `ThrottledRequests` e `OnlineIndexPercentageProgress` do CloudWatch em todo o processo. Ajuste a capacidade de gravação provisionada conforme necessário para concluir o provisionamento em tempo razoável, sem efeitos consideráveis de controle de utilização nas operações em andamento. `OnlineIndexConsumedWriteCapacity` e `OnlineThrottleEvents` devem mostrar 0 durante o preenchimento de índice.
Prepare-se para cancelar a criação do índice, em caso de impacto operacional devido ao controle de utilização de gravação.

## Descrever os índices secundários globais em uma tabela
<a name="GSI.Describing"></a>

Para ver o status de todos os índices secundários globais em uma tabela, use a operação `DescribeTable`. A parte `GlobalSecondaryIndexes` da resposta mostra todos os índices na tabela, juntamente com o status atual de cada (`IndexStatus`).

O `IndexStatus` para um índice secundário global será um dos seguintes:
+ `CREATING`: o índice está sendo criado e ainda não está disponível para uso.
+ `ACTIVE`: o índice está pronto para uso e as aplicações podem executar operações `Query` no índice.
+ `UPDATING`: as configurações de throughput provisionado do índice estão sendo alteradas.
+ `DELETING`: o índice está sendo excluído e não pode mais ser usado.

Quando o DynamoDB tiver terminado de criar um índice secundário global, o status do índice mudará de `CREATING` para `ACTIVE`.

## Adicionar um índice secundário global a uma tabela
<a name="GSI.OnlineOps.Creating"></a>

Para adicionar um índice secundário global a uma tabela existente, use a operação `UpdateTable` com o parâmetro `GlobalSecondaryIndexUpdates`. Você deve fornecer o seguinte:
+ Um nome de índice. O nome deve ser exclusivo entre todos os índices na tabela.
+ O esquema de chave do índice. É necessário especificar um atributo para a chave da partição de índice, mas existe a opção de especificar outro atributo para a chave de classificação de índice. Não é necessário que nenhum desses atributos de chave seja o mesmo que um atributo de chave na tabela. Os tipos de dados de cada atributo de esquema devem ser escalares: `String`, `Number` ou `Binary`.
+ Os atributos a serem projetados da tabela para o índice:
  + `KEYS_ONLY`: cada item do índice consiste apenas nos valores de chaves de partição e nas chaves de classificação da tabela, além dos valores de chaves do índice. 
  + `INCLUDE`: além dos atributos descritos em `KEYS_ONLY`, o índice secundário inclui outros atributos não chave que você especificar.
  + `ALL`:  o índice inclui todos os atributos da tabela de origem.
+ As configurações do throughput provisionado para o índice, formadas por `ReadCapacityUnits` e `WriteCapacityUnits`. Essas configurações de throughput provisionado são distintas daquelas na tabela.

Você pode criar somente um índice secundário global por operação `UpdateTable`.

### Fases da criação de um índice
<a name="GSI.OnlineOps.Creating.Phases"></a>

Quando você adiciona um novo índice secundário global a uma tabela existente, ela continua a estar disponível enquanto o índice está sendo construído. No entanto, o novo índice apenas estará disponível para operações de consulta quando seu status mudar de `CREATING` para `ACTIVE`.

**nota**  
A criação do índice secundário global não usa o Application Auto Scaling. Aumentar a capacidade `MIN` do Application Auto Scaling não diminuirá o tempo de criação do índice secundário global.

Nos bastidores, o DynamoDB constrói o índice em duas fases:

**Alocação de recursos**  
O DynamoDB aloca os recursos de computação e de armazenamento que são necessários para a construção do índice.  
Durante a fase de alocação de recursos, o atributo `IndexStatus` é `CREATING`, enquanto o atributo `Backfilling` é false. Use a operação `DescribeTable` para recuperar o status de uma tabela e todos os índices secundários dela.  
Enquanto o índice estiver na fase de alocação de recurso, você poderá excluí-lo ou a apagar a tabela principal dele. Você também não pode modificar o throughput provisionado do índice ou da tabela. Não é possível adicionar ou excluir outros índices na tabela. No entanto, você pode modificar o throughput provisionado desses outros índices.

**Aterramento**  
Para cada item na tabela, o DynamoDB determina qual conjunto de atributos deve ser gravado no índice com base em sua projeção (`KEYS_ONLY`, `INCLUDE` ou `ALL`). Em seguida, ele grava esses atributos no índice. Durante a fase de preenchimento, o DynamoDB rastreia os itens que estão sendo adicionados, excluídos ou atualizados na tabela. Os atributos desses itens também são adicionados, excluídos ou atualizados no índice conforme apropriado.  
Durante a fase de preenchimento, o atributo `IndexStatus` é definido como `CREATING`, e o atributo `Backfilling` é verdadeiro. Use a operação `DescribeTable` para recuperar o status de uma tabela e todos os índices secundários dela.  
Enquanto o índice está em processo de aterramento, não é possível excluir a tabela principal. No entanto, ainda é possível excluir o índice ou modificar o throughput provisionado da tabela e de qualquer um dos seus índices secundários globais.  
Durante a fase de aterramento, algumas gravações de itens infratores podem ter sucesso, enquanto outras serão rejeitadas. Após o aterramento, todas as gravações de itens que violarem o esquema de chaves do novo índice serão rejeitadas. Recomendamos executar a ferramenta Violation Detector após a conclusão da fase de preenchimento em segundo plano, para detectar e resolver qualquer infração de chave que possa ter ocorrido. Para obter mais informações, consulte [Detectar e corrigir violações de chave de índice no DynamoDB](GSI.OnlineOps.ViolationDetection.md).

Enquanto as fases de alocação de recurso e aterramento estão em andamento, o índice permanece no estado `CREATING`. Enquanto isso, o DynamoDB executa operações de leitura na tabela. Você não é cobrado pelas operações de leitura da tabela-base para preencher o índice secundário global.

Quando a construção do índice estiver concluída, seu status mudará para `ACTIVE`. Você não pode executar `Query` ou `Scan` no índice até que ele esteja no modo `ACTIVE`.

**nota**  
Em alguns casos, o DynamoDB não pode gravar dados da tabela no índice devido a violações de chaves de índice. Isso poderá ocorrer se:  
O tipo de dados de um valor de atributo não corresponder ao tipo de dados de um esquema de chaves de índice.
O tamanho de um atributo excede o tamanho máximo de um atributo de chave de índice.
Um atributo de chave de índice tem um valor binários ou de string vazio.
Violações de chaves de índice não interferem na criação do índice secundário global. No entanto, quando o índice ficar `ACTIVE`, as chaves infratoras não estarão presentes no índice.  
O DynamoDB fornece uma ferramenta autônoma para localizar e resolver esses problemas. Para obter mais informações, consulte [Detectar e corrigir violações de chave de índice no DynamoDB](GSI.OnlineOps.ViolationDetection.md).

### Adicionar um índice secundário global a uma tabela grande
<a name="GSI.OnlineOps.Creating.LargeTable"></a>

O tempo necessário para a construção de um índice secundário global depende de vários fatores, entre eles:
+ O tamanho da tabela
+ O número de itens na tabela que se qualificam para inclusão no índice
+ O número de atributos projetados no índice
+ A atividade de gravação na tabela principal durante a criação dos índices

Se você estiver adicionando um índice secundário global a uma tabela muito grande, a conclusão do processo de criação poderá ser demorada. Para monitorar o progresso e determinar se o índice tem capacidade de gravação suficiente, consulte as seguintes métricas do Amazon CloudWatch:
+ `OnlineIndexPercentageProgress`

Para obter mais informações sobre as métricas do CloudWatch relacionadas ao DynamoDB, consulte [Métricas do DynamoDB](metrics-dimensions.md#dynamodb-metrics).

**Importante**  
Talvez seja necessário incluir tabelas muito grandes na lista de permissões antes de criar ou atualizar um índice secundário global. Entre em contato com o AWS Support para incluir tabelas na lista de permissões.

Enquanto um índice está sendo preenchido em segundo plano, o DynamoDB usa a capacidade do sistema interno para fazer leituras na tabela. Isso é feito para minimizar o impacto da criação do índice e garantir que sua tabela não fique sem capacidade de leitura.

## Exclusão de um índice secundário global
<a name="GSI.OnlineOps.Deleting"></a>

Se você não precisa mais de um índice secundário global, pode excluí-lo usando a operação `UpdateTable`.

É possível excluir somente um índice secundário global por operação `UpdateTable`.

Enquanto o índice secundário global está sendo excluído, não há efeitos sobre atividades de leitura ou de gravação na tabela principal. Enquanto a exclusão está em andamento, você ainda pode modificar o throughput provisionado em outros índices.

**nota**  
Quando você exclui uma tabela usando a ação `DeleteTable`, todos os índices secundários globais nessa tabela também são excluídos.
Sua conta não será cobrada pela operação de exclusão do índice secundário global.

## Modificar um índice secundário global durante a criação
<a name="GSI.OnlineOps.Creating.Modify"></a>

Enquanto um índice está sendo construído, é possível usar a operação `DescribeTable` para determinar em qual fase ele se encontra. A descrição do índice inclui um atributo booleano, `Backfilling`, para indicar se o DynamoDB está carregando o índice com itens da tabela no momento. Se `Backfilling` for verdadeiro, a fase de alocação de recursos estará concluída, e o índice agora estará sendo preenchido. 

Durante a fase de aterramento, é possível excluir o índice que está sendo criado. Durante essa fase, não é possível adicionar ou excluir outros índices na tabela.

**nota**  
Para índices que foram criados como parte de uma operação `CreateTable`, o atributo `Backfilling` não aparece na saída de `DescribeTable`. Para obter mais informações, consulte [Fases da criação de um índice](#GSI.OnlineOps.Creating.Phases).

# Detectar e corrigir violações de chave de índice no DynamoDB
<a name="GSI.OnlineOps.ViolationDetection"></a>

Durante a fase de preenchimento em segundo plano da criação de um índice secundário global, o Amazon DynamoDB examina cada item na tabela para determinar se ele está qualificado para inclusão no índice. Alguns itens podem não ser qualificados, pois causariam violações de chave de índice. Nesses casos, os itens permanecerão na tabela, mas o índice não terá uma entrada correspondente para eles.

Uma *infração na chave do índice* ocorre nas seguintes situações:
+ Há uma inconsistência de tipo de dados entre um valor de atributo e o tipo de dados do esquema de chaves de índice. Por exemplo, suponha que um dos itens na tabela `GameScores` tivesse um valor `TopScore` do tipo `String`. Se você adicionasse um `TopScore` com uma chave de partição de do tipo `Number`, o item da tabela violaria a chave de índice.
+ Um valor de atributo da tabela excede o comprimento máximo para um atributo de chave de índice. O comprimento máximo de uma chave de partição é 2048 bytes, enquanto o comprimento máximo de uma chave de classificação é 1024 bytes. Se qualquer um dos valores de atributo correspondente na tabela exceder esses limites, o item da tabela violará a chave de índice.

**nota**  
Se um valor de atributo binário ou de string for definido para um atributo usado como uma chave de índice, o valor do atributo deverá ter um tamanho maior que zero. Caso contrário, o item da tabela violaria a chave de índice.  
Esta ferramenta não sinaliza esta infração na chave do índice neste momento.

Se uma infração na chave do índice ocorrer, a fase de preenchimento em segundo plano continuará sem interrupção. No entanto, os itens infratores não são incluídos no índice. Concluída a fase de aterramento, todas as gravações em itens que violam o esquema de chaves do novo índice serão rejeitadas.

Para identificar e corrigir os valores de atributos em uma tabela que violam uma chave de índice, use a ferramenta Violation Detector. Para executar o Violation Detector, crie um arquivo de configuração que especifique o nome de uma tabela a ser verificada, os nomes e os tipos de dados da chave de partição do índice secundário global e a chave de classificação, bem como quais ações deverão ser realizadas se violações de chave de índice forem encontradas. O Violation Detector pode ser executado em um destes dois diferentes modos:
+ **Modo de detecção**: detecta violações de chave de índice. Use o modo de detecção para informar os itens na tabela que causariam violações de chaves em um índice secundário global. (Você tem a opção de solicitar que esses itens de tabela infratores sejam excluídos imediatamente quando forem encontrados.) A saída do modo de detecção é gravada em um arquivo, que você pode usar para análise posterior.
+ **Modo de correção**: corrige violações de chaves de índice. No modo de correção, o Violation Detector lê um arquivo de entrada com o mesmo formato que o arquivo de saída do modo de detecção. O modo de correção lê os registros do arquivo de entrada e, para cada registro, ele exclui ou atualiza os itens correspondentes na tabela. (Observe que, se você optar por atualizar os itens, deverá editar o arquivo de entrada e definir os valores apropriados para essas atualizações.)

## Baixar e executar o Violation Detector
<a name="GSI.OnlineOps.ViolationDetection.Running"></a>

O Violation Detector está disponível como um arquivo Java executável (arquivo `.jar`) e pode ser executado em computadores Windows, Mac ou Linux. O Violation Detector requer o Java 1.7 (ou posterior) e o Apache Maven.
+ [Baixar o Violation Detector do GitHub](https://github.com/awslabs/dynamodb-online-index-violation-detector)

Siga as instruções no arquivo `README.md` para fazer download e instalar o Violation Detector usando o Maven.

Para iniciar o Violation Detector, acesse o diretório no qual você compilou o arquivo `ViolationDetector.java` e insira o seguinte comando:

```
java -jar ViolationDetector.jar [options]
```

A linha de comando do Violation Detector aceita as seguintes opções:
+ `-h | --help`: imprime um resumo de uso e opções do Violation Detector.
+ `-p | --configFilePath` `value`: o nome totalmente qualificado de um arquivo de configuração do Violation Detector. Para obter mais informações, consulte [O arquivo de configuração do Violation Detector](#GSI.OnlineOps.ViolationDetection.ConfigFile).
+ `-t | --detect` `value`: detecta violações de chave de índice na tabela e as grava no arquivo de saída do Violation Detector. Se o valor desse parâmetro for definido como `keep`, os itens com violações de chave não serão modificados. Se o valor for definido como `delete`, os itens com violações de chave serão excluídos da tabela.
+ `-c | --correct` `value`: lê violações de chave de índice de um arquivo de entrada e toma ações corretivas nos itens da tabela. Se o valor desse parâmetro for definido como `update`, os itens com violações de chave serão atualizados com valores novos não infratores. Se o valor for definido como `delete`, os itens com violações de chave serão excluídos da tabela.

## O arquivo de configuração do Violation Detector
<a name="GSI.OnlineOps.ViolationDetection.ConfigFile"></a>

Em tempo de execução, a ferramenta Violation Detector requer um arquivo de configuração Os parâmetros nesse arquivo determinam quais recursos do DynamoDB o Violation Detector pode acessar e quanto throughput provisionado ele pode consumir. A tabela a seguir descreve esses parâmetros.


****  

| Nome do parâmetro | Descrição | Obrigatório? | 
| --- | --- | --- | 
|  `awsCredentialsFile`  |  O nome totalmente qualificado de um arquivo que contém suas credenciais da AWS. O arquivo de credenciais deve estar no seguinte formato: <pre>accessKey = access_key_id_goes_here<br />secretKey = secret_key_goes_here </pre>  |  Sim  | 
|  `dynamoDBRegion`  |  A região da AWS na qual a tabela reside. Por exemplo: `us-west-2`.  |  Sim  | 
|  `tableName`  | O nome da tabela do DynamoDB a ser verificada. |  Sim  | 
|  `gsiHashKeyName`  |  O nome da chave de partição do índice.  |  Sim  | 
|  `gsiHashKeyType`  |  O tipo de dados da chave de partição do índice: `String`, `Number` ou `Binary` `S \| N \| B`  |  Sim  | 
|  `gsiRangeKeyName`  |  O nome da chave de classificação do índice. Não especifique esse parâmetro se o índice tiver apenas uma chave primária simples (chave de partição).  |  Não  | 
|  `gsiRangeKeyType`  |  O tipo de dados da chave de classificação do índice: `String`, `Number` ou `Binary` `S \| N \| B`  Não especifique esse parâmetro se o índice tiver apenas uma chave primária simples (chave de partição).  |  Não  | 
|  `recordDetails`  |  Se você deseja gravar os detalhes completos das violações de chaves de índice no arquivo de saída. Se a opção for definida como `true` (o padrão), todas as informações sobre os itens infratores serão relatadas. Se definido como `false`, apenas o número de violações será relatado.  |  Não  | 
|  `recordGsiValueInViolationRecord`  |  Se você deseja gravar os valores das chaves de índice infratoras no arquivo de saída. Se a opção for definida como `true` (padrão), os valores das chaves serão relatados. Se definido como `false`, os valores das chave não serão relatados.  |  Não  | 
|  `detectionOutputPath`  |  O caminho completo do arquivo de saída do Violation Detector. Esse parâmetro oferece suporte à gravação em um diretório local ou no Amazon Simple Storage Service (Amazon S3). Veja os exemplos a seguir: `detectionOutputPath = ``//local/path/filename.csv` `detectionOutputPath = ``s3://bucket/filename.csv` As informações no arquivo de saída são mostradas no formato CSV (valores separados por vírgula). Se você não definir `detectionOutputPath`, o arquivo de saída se chamará `violation_detection.csv` e será gravado no seu diretório de trabalho atual.  |  Não  | 
|  `numOfSegments`  | O número de segmentos de verificação paralela a serem usados quando o Violation Detector verificar a tabela. O valor padrão é 1, o que significa que a tabela é verificada de maneira sequencial. Se o valor for 2 ou superior, o Violation Detector dividirá a tabela no número correspondente de segmentos lógicos e em um número igual de threads de verificação. A configuração máxima para `numOfSegments` é 4096.Para tabelas maiores, uma verificação paralela é geralmente mais rápida do que uma verificação sequencial. Além disso, se a tabela for grande o suficiente para abranger várias partições, uma verificação paralela distribui sua atividade de leitura uniformemente entre essas várias partições.Para obter mais informações sobre verificações paralelas no DynamoDB, consulte [Verificar em paralelo](Scan.md#Scan.ParallelScan). |  Não  | 
|  `numOfViolations`  |  O limite superior de violações de chaves de índice a serem gravadas no arquivo de saída. Se definido como `-1` (o padrão), a tabela inteira é verificada. Se definido como um número inteiro positivo, o Violation Detector será interrompido quando encontrar esse número de violações.  |  Não  | 
|  `numOfRecords`  |  O número de itens na tabela a ser verificada. Se definido como -1 (o padrão), a tabela inteira é verificada. Se definido como um número inteiro positivo, o Violation Detector será interrompido após verificar o mesmo número de itens na tabela.  |  Não  | 
|  `readWriteIOPSPercent`  |  Regula a porcentagem de unidades de capacidade de leitura provisionada que são consumidas durante a verificação de tabela. Os valores válidos variam de `1` até `100`. O valor padrão (`25`) significa que o Violation Detector não consumirá mais de 25% do throughput provisionado da tabela.  |  Não  | 
|  `correctionInputPath`  |  O caminho completo do arquivo de entrada de correção do Violation Detector. Se você executar o Violation Detector no modo de correção, o conteúdo desse arquivo será usado para modificar ou excluir os itens de dados na tabela que violam o índice secundário global. O formato do arquivo `correctionInputPath` é o mesmo que o do arquivo `detectionOutputPath`. Isso permite que você processe a saída do modo de detecção como uma entrada no modo de correção.  |  Não  | 
|  `correctionOutputPath`  |  O caminho completo do arquivo de saída de correção do Violation Detector. Esse arquivo será criado somente se houver erros de atualização. Esse parâmetro oferece suporte à gravação em um diretório local ou no Amazon S3. Veja os exemplos a seguir: `correctionOutputPath = ``//local/path/filename.csv` `correctionOutputPath = ``s3://bucket/filename.csv` As informações no arquivo de saída são mostradas no formato CSV. Se você não definir `correctionOutputPath`, o arquivo de saída se chamará `violation_update_errors.csv` e será gravado no seu diretório de trabalho atual.  |  Não  | 

## Detecção
<a name="GSI.OnlineOps.ViolationDetection.Detection"></a>

Para detectar violações de chave de índice, use o Violation Detector com a opção de linha de comando `--detect`. Para mostrar como essa opção funciona, considere a tabela `ProductCatalog`. Veja a seguir uma lista de itens na tabela. Apenas a chave primária (`Id`) e o atributo `Price` são mostrados.


****  

| ID (chave primária) | Preço | 
| --- | --- | 
| 101 |  5  | 
| 102 |  20  | 
| 103 | 200  | 
| 201 |  100  | 
| 202 |  200  | 
| 203 |  300  | 
| 204 |  400  | 
| 205 |  500  | 

Todos os valores para `Price` são do tipo `Number`. No entanto, como o DynamoDB não tem esquema, é possível adicionar um item com um não numérico `Price`. Por exemplo, suponha que adicionemos outro item à tabela `ProductCatalog`:


****  

| ID (chave primária) | Preço | 
| --- | --- | 
| 999 | "Hello" | 

Agora, a tabela tem um total de nove itens.

Agora você adiciona um novo índice secundário global à tabela: `PriceIndex`. A chave primária desse índice é uma chave de partição, `Price`, do tipo `Number`. Depois que o índice tiver sido construído, ele conterá oito itens, mas a tabela `ProductCatalog` tem nove itens. O motivo dessa discrepância é que o valor `"Hello"` é do tipo `String`, mas `PriceIndex` tem uma chave primária do tipo `Number`. O valor de `String` viola a chave do índice secundário global e, por isso, não está presente no índice.

Para usar o Violation Detector nesse cenário, você primeiro deve criar um arquivo de configuração como este.

```
# 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
```

Em seguida, execute o Violation Detector como no exemplo a seguir.

```
$  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
```

Se o parâmetro de configuração `recordDetails` for definido como `true`, o Violation Detector gravará os detalhes de cada infração no arquivo de saída, como no exemplo a seguir.

```
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,,
```

O arquivo de saída está no formato CSV. A primeira linha do arquivo é um cabeçalho, seguida de um registro por item que viola a chave de índice. Os campos desses registros infratores são os seguintes:
+ **Table Hash Key** (Chave de hash da tabela): o valor da chave de partição do item na tabela.
+ **Table Range Key** (Chave de classificação da tabela): o valor da chave de classificação do item na tabela.
+ **GSI Hash Key Value** (Valor da chave de hash do GSI): o valor da chave de partição do índice secundário global.
+ **GSI Hash Key Violation Type** (Tipo de violação da chave de hash do GSI): `Type Violation` ou `Size Violation`.
+ **GSI Hash Key Violation Description** (Descrição da violação da chave de hash do GSI): a causa da infração.
+ **GSI Hash Key Update Value(FORUSER)** (Valor da atualização da chave de hash do GSI [PARA USUÁRIO]): no modo de correção, um novo valor fornecido pelo usuário para o atributo.
+ **GSI Hash Key Value** (Valor da chave de hash do GSI): o valor da chave de classificação do índice secundário global.
+ **GSI Range Key Violation Type** (Tipo de violação da chave de intervalo do GSI: `Type Violation` ou `Size Violation`.
+ **GSI Range Key Violation Description** (Descrição da violação da chave de intervalo do GSI): a causa da infração.
+ **GSI Range Key Update Value(FOR USER)** (Valor da atualização da chave de intervalo do GSI [PARA USUÁRIO]: no modo de correção, um novo valor fornecido pelo usuário para o atributo.
+ **Delete Blank Attribute When Updating(Y/N)** (Excluir atributo em branco ao atualizar[S/N]): no modo de correção, determina se o item infrator deve ser excluído (Y) ou mantido (N) na tabela, mas apenas se algum dos seguintes campos estiver em branco:
  + `GSI Hash Key Update Value(FOR USER)`
  + `GSI Range Key Update Value(FOR USER)`

  Se qualquer um desses campos não estiver em branco, `Delete Blank Attribute When Updating(Y/N)` não terá efeito.

**nota**  
O formato de saída pode variar dependendo do arquivo de configuração e das opções da linha de comando. Por exemplo, se a tabela tiver uma chave primária simples (sem uma chave de classificação), nenhum campo de chave de classificação estará presente na saída.  
Os registros de infração no arquivo podem não estar na ordem classificada.

## Correção
<a name="GSI.OnlineOps.ViolationDetection.Correction"></a>

Para corrigir violações de chave de índice, use o Violation Detector com a opção de linha de comando `--correct`. No modo de correção, o Violation Detector lê o arquivo de entrada especificado pelo parâmetro `correctionInputPath`. Esse arquivo tem o mesmo formato que o arquivo `detectionOutputPath` e, portanto, você pode usar a saída da detecção como a entrada para a correção.

O Violation Detector fornece duas maneiras diferentes para corrigir violações de chave de índice:
+ **Excluir violações**: exclua os itens da tabela que possuem valores de atributo infratores.
+ **Atualizar violações**: atualize os itens da tabela substituindo os atributos infratores por valores não infratores.

Em ambos os casos, você pode usar o arquivo de saída do modo de detecção como uma entrada para o modo de correção.

Continuando com o exemplo de `ProductCatalog`, suponha que queiramos excluir o item infrator da tabela. Para fazer isso, use a seguinte linha de comando:

```
$  java -jar ViolationDetector.jar --configFilePath config.txt --correct delete
```

Neste ponto, você será solicitado a confirmar se deseja excluir os itens infratores.

```
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
```

Agora, tanto `ProductCatalog` quanto `PriceIndex` têm o mesmo número de itens.

# Como trabalhar com índices secundários globais: Java
<a name="GSIJavaDocumentAPI"></a>

Você pode usar a API de documentos do AWS SDK para Java para criar uma tabela do Amazon DynamoDB com um ou mais índices secundários globais na tabela e executar consultas usando os índices. 

Veja a seguir as etapas comuns para as operações de tabela. 

1. Crie uma instância da classe `DynamoDB`.

1. Forneça os parâmetros obrigatórios e opcionais para a operação, criando os objetos de solicitação correspondentes. 

1. Chame o método apropriado fornecido pelo cliente que você criou na etapa anterior. 

**Topics**
+ [Criar uma tabela com um índice secundário global](#GSIJavaDocumentAPI.CreateTableWithIndex)
+ [Descrever uma tabela com um índice secundário global](#GSIJavaDocumentAPI.DescribeTableWithIndex)
+ [Consultar um índice secundário global](#GSIJavaDocumentAPI.QueryAnIndex)
+ [Exemplo: índices secundários globais que usam a API de documento do AWS SDK para Java](GSIJavaDocumentAPI.Example.md)

## Criar uma tabela com um índice secundário global
<a name="GSIJavaDocumentAPI.CreateTableWithIndex"></a>

Você pode criar índices secundários globais ao mesmo tempo em que cria uma tabela. Para fazer isso, use `CreateTable` e forneça suas especificações para um ou mais índices secundários globais. O exemplo de código Java a seguir cria uma tabela para armazenar informações sobre dados climáticos. A chave de partição é `Location` e a chave de classificação é `Date`. Um índice secundário global chamado `PrecipIndex` permite acesso rápido aos dados de precipitação de vários locais.

Veja a seguir as etapas necessárias para criar uma tabela com um índice secundário global usando a API de documentos do DynamoDB. 

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `CreateTableRequest` para fornecer as informações solicitadas.

   Você deve fornecer o nome da tabela, sua chave primária e os valores de throughput provisionado. Para o índice secundário global, você deve fornecer o nome do índice, suas configurações de throughput provisionado, as definições de atributo da chave de classificação do índice, o esquema de chaves do índice e a projeção do atributo.

1. Chame o método `createTable`, fornecendo o objeto de solicitação como um parâmetro.

O exemplo de código Java a seguir demonstra as etapas anteriores. O código cria uma tabela (`WeatherData`) com um índice secundário global (`PrecipIndex`). A chave de partição do índice é `Date` e a chave de classificação é `Precipitation`. Todos os atributos da tabela estão projetados no índice. Os usuários podem consultar esse índice para obter dados climáticos de uma data específica, opcionalmente, classificar os dados por quantidade de precipitação. 

Como `Precipitation` não é um atributo de chave para a tabela, ele não é necessário. No entanto, os itens de `WeatherData` sem `Precipitation` não aparecem no `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());
```

Você deve aguardar até que o DynamoDB crie a tabela e defina o status dessa tabela como `ACTIVE`. Depois disso, você poderá começar a inserir itens de dados na tabela.

## Descrever uma tabela com um índice secundário global
<a name="GSIJavaDocumentAPI.DescribeTableWithIndex"></a>

Para obter mais informações sobre índices secundários globais em uma tabela, use `DescribeTable`. Para cada índice, você pode acessar seu nome, esquema de chaves e atributos projetados.

Veja a seguir as etapas necessárias para acessar informações de índice secundário global em uma tabela. 

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `Table` para representar o índice com o qual você deseja trabalhar.

1. Chame o método `describe` no objeto `Table`.

O exemplo de código Java a seguir demonstra as etapas anteriores.

**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());
    }
}
```

## Consultar um índice secundário global
<a name="GSIJavaDocumentAPI.QueryAnIndex"></a>

Você pode usar `Query` em um índice secundário global de forma semelhante ao uso de `Query` em uma tabela. Você precisa especificar o nome do índice, os critérios de consulta da chave de partição e da chave de classificação (se houver) do índice, e os atributos que você deseja retornar. Neste exemplo, o índice é `PrecipIndex`, que tem uma chave de partição `Date` e uma chave de classificação `Precipitation`. A consulta de índice retorna todos os dados climáticos de uma data específica, na qual a precipitação é maior que zero.

Veja a seguir as etapas necessárias para consultar um índice secundário global usando a API de documentos do AWS SDK para Java. 

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `Table` para representar o índice com o qual você deseja trabalhar.

1. Crie uma instância da classe `Index` para o índice que deseja consultar.

1. Chame o método `query` no objeto `Index`.

O nome do atributo `Date` é uma palavra reservada do DynamoDB. Portanto, use um nome de atributo de expressão como um espaço reservado na `KeyConditionExpression`.

O exemplo de código Java a seguir demonstra as etapas anteriores.

**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());
}
```

# Exemplo: índices secundários globais que usam a API de documento do AWS SDK para Java
<a name="GSIJavaDocumentAPI.Example"></a>

O código Java de exemplo a seguir mostra como trabalhar com índices secundários globais. O exemplo cria uma tabela chamada `Issues`, que pode ser usada em um sistema de controle de bugs simples para desenvolvimento de software. A chave de partição é `IssueId` e a chave de classificação é `Title`. Há três índices secundários globais nessa tabela:
+ `CreateDateIndex`: a chave de partição é `CreateDate` e a chave de classificação é `IssueId`. Além das chaves da tabela, os atributos `Description` e `Status` são projetados no índice.
+ `TitleIndex`: a chave de partição é `Title` e a chave de classificação é `IssueId`. Nenhum outro atributo além das chaves da tabela são projetos no índice.
+ `DueDateIndex`: a chave de partição é `DueDate` e não há chave de classificação. Todos os atributos da tabela estão projetados no índice.

Depois que a tabela `Issues` é criada, o programa carrega a tabela com os dados que representam relatórios de bugs do software. Ele consulta os dados usando os índices secundários globais. Por fim, o programa exclui a tabela `Issues`.

Para obter instruções passo a passo sobre como testar o exemplo a seguir, consulte [Exemplos de código 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);
    }

}
```

# Como trabalhar com índices secundários globais: .NET
<a name="GSILowLevelDotNet"></a>

Você pode usar a API de baixo nível do AWS SDK para .NET para criar uma tabela do Amazon DynamoDB com um ou mais índices secundários globais na tabela e executar consultas usando os índices. Essas operações são mapeadas nas operações do DynamoDB correspondentes. Para obter mais informações, consulte a [Referência de API do Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/). 

Veja a seguir as etapas comuns para operações de tabela usando a API de baixo nível do .NET. 

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Forneça os parâmetros obrigatórios e opcionais para a operação, criando os objetos de solicitação correspondentes.

   Por exemplo, crie um objeto `CreateTableRequest` para criar uma tabela e um objeto `QueryRequest` para consultar uma tabela ou um índice. 

1. Execute o método apropriado fornecido pelo cliente que você criou na etapa anterior. 

**Topics**
+ [Criar uma tabela com um índice secundário global](#GSILowLevelDotNet.CreateTableWithIndex)
+ [Descrever uma tabela com um índice secundário global](#GSILowLevelDotNet.DescribeTableWithIndex)
+ [Consultar um índice secundário global](#GSILowLevelDotNet.QueryAnIndex)
+ [Exemplo: índices secundários globais que usam a API de baixo nível do AWS SDK para .NET](GSILowLevelDotNet.Example.md)

## Criar uma tabela com um índice secundário global
<a name="GSILowLevelDotNet.CreateTableWithIndex"></a>

Você pode criar índices secundários globais ao mesmo tempo em que cria uma tabela. Para fazer isso, use `CreateTable` e forneça suas especificações para um ou mais índices secundários globais. O exemplo de código C\$1a seguir cria uma tabela para armazenar informações sobre dados climáticos. A chave de partição é `Location` e a chave de classificação é `Date`. Um índice secundário global chamado `PrecipIndex` permite acesso rápido aos dados de precipitação de vários locais.

Veja a seguir as etapas necessárias para criar uma tabela com um índice secundário global usando a API de baixo nível do .NET. 

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Crie uma instância da classe `CreateTableRequest` para fornecer as informações solicitadas. 

   Você deve fornecer o nome da tabela, sua chave primária e os valores de throughput provisionado. Para o índice secundário global, você deve fornecer o nome do índice, suas configurações de throughput provisionado, as definições de atributo da chave de classificação do índice, o esquema de chaves do índice e a projeção do atributo.

1. Execute o método `CreateTable` fornecendo o objeto de solicitação como um parâmetro.

O exemplo de código C\$1 a seguir demonstra as etapas anteriores. O código cria uma tabela (`WeatherData`) com um índice secundário global (`PrecipIndex`). A chave de partição do índice é `Date` e a chave de classificação é `Precipitation`. Todos os atributos da tabela estão projetados no índice. Os usuários podem consultar esse índice para obter dados climáticos de uma data específica, opcionalmente, classificar os dados por quantidade de precipitação. 

Como `Precipitation` não é um atributo de chave para a tabela, ele não é necessário. No entanto, os itens de `WeatherData` sem `Precipitation` não aparecem no `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);
```

Você deve aguardar até que o DynamoDB crie a tabela e defina o status dessa tabela como `ACTIVE`. Depois disso, você poderá começar a inserir itens de dados na tabela.

## Descrever uma tabela com um índice secundário global
<a name="GSILowLevelDotNet.DescribeTableWithIndex"></a>

Para obter mais informações sobre índices secundários globais em uma tabela, use `DescribeTable`. Para cada índice, você pode acessar seu nome, esquema de chaves e atributos projetados.

Veja a seguir as etapas para acessar informações do índice secundário global para uma tabela usando a API de baixo nível do .NET. 

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Execute o método `describeTable` fornecendo o objeto de solicitação como um parâmetro.

   Crie uma instância da classe `DescribeTableRequest` para fornecer as informações solicitadas. Você deve fornecer o nome da tabela.

O exemplo de código C\$1 a seguir demonstra as etapas anteriores.

**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);
      }
}
```

## Consultar um índice secundário global
<a name="GSILowLevelDotNet.QueryAnIndex"></a>

Você pode usar `Query` em um índice secundário global de forma semelhante ao uso de `Query` em uma tabela. Você precisa especificar o nome do índice, os critérios de consulta da chave de partição e da chave de classificação (se houver) do índice, e os atributos que você deseja retornar. Neste exemplo, o índice é `PrecipIndex`, que tem uma chave de partição `Date` e uma chave de classificação `Precipitation`. A consulta de índice retorna todos os dados climáticos de uma data específica, na qual a precipitação é maior que zero.

Veja a seguir as etapas para consultar um índice secundário global usando a API de baixo nível do .NET. 

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Crie uma instância da classe `QueryRequest` para fornecer as informações solicitadas.

1. Execute o método `query` fornecendo o objeto de solicitação como um parâmetro.

O nome do atributo `Date` é uma palavra reservada do DynamoDB. Portanto, use um nome de atributo de expressão como um espaço reservado na `KeyConditionExpression`.

O exemplo de código C\$1 a seguir demonstra as etapas anteriores.

**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();
}
```

# Exemplo: índices secundários globais que usam a API de baixo nível do AWS SDK para .NET
<a name="GSILowLevelDotNet.Example"></a>

O código de exemplo Java a seguir mostra como trabalhar com índices secundários globais. O exemplo cria uma tabela chamada `Issues`, que pode ser usada em um sistema de controle de bugs simples para desenvolvimento de software. A chave de partição é `IssueId` e a chave de classificação é `Title`. Há três índices secundários globais nessa tabela:
+ `CreateDateIndex`: a chave de partição é `CreateDate` e a chave de classificação é `IssueId`. Além das chaves da tabela, os atributos `Description` e `Status` são projetados no índice.
+ `TitleIndex`: a chave de partição é `Title` e a chave de classificação é `IssueId`. Nenhum outro atributo além das chaves da tabela são projetos no índice.
+ `DueDateIndex`: a chave de partição é `DueDate` e não há chave de classificação. Todos os atributos da tabela estão projetados no índice.

Depois que a tabela `Issues` é criada, o programa carrega a tabela com os dados que representam relatórios de bugs do software. Ele consulta os dados usando os índices secundários globais. Por fim, o programa exclui a tabela `Issues`.

Para obter instruções detalhadas sobre como testar o exemplo a seguir, consulte [Exemplos de código .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;
                }
            }
        }
    }
}
```

# Trabalhar com índices secundários globais no DynamoDB usando a AWS CLI
<a name="GCICli"></a>

Você pode usar a AWS CLI para criar uma tabela do Amazon DynamoDB com um ou mais índices secundários globais na tabela e executar consultas usando os índices.

**Topics**
+ [Criar uma tabela com um índice secundário global](#GCICli.CreateTableWithIndex)
+ [Adicionar um índice secundário global a uma tabela existente](#GCICli.CreateIndexAfterTable)
+ [Descrever uma tabela com um índice secundário global](#GCICli.DescribeTableWithIndex)
+ [Consultar um índice secundário global](#GCICli.QueryAnIndex)

## Criar uma tabela com um índice secundário global
<a name="GCICli.CreateTableWithIndex"></a>

Você pode criar índices secundários globais ao mesmo tempo que cria uma tabela. Para fazer isso, use o parâmetro `create-table` e forneça suas especificações para um ou mais índices secundários globais. O exemplo a seguir cria uma tabela chamada `GameScores` com um índice secundário global chamado `GameTitleIndex`. A tabela-base tem uma chave de partição `UserId` e uma chave de classificação `GameTitle`, permitindo que você encontre a melhor pontuação de um usuário individual para um jogo específico de forma eficiente, enquanto o GSI tem uma chave de partição `GameTitle` e uma chave de classificação `TopScore`, permitindo que você encontre rapidamente a pontuação mais alta geral para um jogo específico.

```
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
                }
            }
        ]"
```

Você deve aguardar até que o DynamoDB crie a tabela e defina o status dessa tabela como `ACTIVE`. Depois disso, você poderá começar a inserir itens de dados na tabela. Você pode usar [describe-table](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/describe-table.html) para determinar o status da criação da tabela.

## Adicionar um índice secundário global a uma tabela existente
<a name="GCICli.CreateIndexAfterTable"></a>

Os índices secundários globais também podem ser adicionados ou modificados após a criação da tabela. Para fazer isso, use o parâmetro `update-table` e forneça suas especificações para um ou mais índices secundários globais. O exemplo a seguir usa o mesmo esquema do exemplo anterior, mas pressupõe que a tabela já foi criada e que adicionaremos o GSI mais tarde.

```
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\"]
                    }
                }
            }
        ]"
```

## Descrever uma tabela com um índice secundário global
<a name="GCICli.DescribeTableWithIndex"></a>

Para obter mais informações sobre índices secundários globais em uma tabela, use o parâmetro `describe-table`. Para cada índice, você pode acessar seu nome, esquema de chaves e atributos projetados.

```
aws dynamodb describe-table --table-name GameScores
```

## Consultar um índice secundário global
<a name="GCICli.QueryAnIndex"></a>

Você pode usar a operação `query` em um índice secundário global de forma semelhante ao uso de `query` em uma tabela. Você deve especificar o nome do índice, os critérios de consulta da chave de classificação do índice e os atributos que deseja retornar. Neste exemplo, o índice é `GameTitleIndex` e a chave de classificação do índice é `GameTitle`.

Os únicos atributos retornados são aqueles que foram projetados no índice. É possível modificar essa consulta para selecionar atributos não chave também, mas isso exigiria atividades de busca de tabela que são relativamente caras. Para obter mais informações sobre buscas de tabela, consulte [Projeções de atributo](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"} }'
```

# Índices secundários locais
<a name="LSI"></a>

Alguns aplicativos só precisam consultar dados usando a chave primária da tabela base. No entanto, podem haver situações em que uma chave de classificação alternativa seria útil. Para oferecer à sua aplicação opções de chaves de classificação, você pode criar um ou mais índices secundários locais em uma tabela do Amazon DynamoDB e emitir solicitações de `Query` ou `Scan` nesses índices.

**Topics**
+ [Cenário: Uso de um índice secundário local](#LSI.Scenario)
+ [Projeções de atributo](#LSI.Projections)
+ [Criação de um índice secundário local](#LSI.Creating)
+ [Ler dados de um índice secundário local](#LSI.Reading)
+ [Gravações de itens e índices secundários locais](#LSI.Writes)
+ [Considerações sobre throughput provisionado para índices secundários locais](#LSI.ThroughputConsiderations)
+ [Considerações sobre armazenamento para índices secundários locais](#LSI.StorageConsiderations)
+ [Conjuntos de itens em índices secundários locais](#LSI.ItemCollections)
+ [Como trabalhar com índices secundários locais: Java](LSIJavaDocumentAPI.md)
+ [Como trabalhar com índices secundários locais: .NET](LSILowLevelDotNet.md)
+ [Trabalhar com índices secundários locais no DynamoDB usando a AWS CLI](LCICli.md)

## Cenário: Uso de um índice secundário local
<a name="LSI.Scenario"></a>

Como exemplo, considere a tabela `Thread`. Esta tabela é útil para aplicações como os [Fóruns de discussão da AWS](https://forums.aws.amazon.com/). O diagrama a seguir mostra como os itens da tabela seriam organizados. (Nem todos os atributos são mostrados.)

![\[A tabela Thread que contém uma lista de nomes, assuntos, hora da última publicação e o número de repostas do fórum.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/LSI_01.png)


O DynamoDB armazena continuamente todos os itens com o mesmo valor de chave de partição. Neste exemplo, dado um determinado `ForumName`, uma operação `Query` poderia localizar imediatamente todos os threads desse fórum. Em um grupo de itens com o mesmo valor de chave de partição, os itens são classificados pelo valor de chave de classificação. Se a chave de classificação (`Subject`) também for fornecida na consulta, o DynamoDB poderá reduzir os resultados que são retornados. Por exemplo, retornar todos os threads do fórum "S3" em que `Subject` começa com a letra "a".

Algumas solicitações podem exigir padrões mais complexos de acesso aos dados. Por exemplo:
+ Quais threads do fórum recebem visualizações e respostas?
+ Qual thread em um determinado fórum tem o maior número de mensagens?
+ Quantos threads foram publicados em um fórum específico em um determinado período?

A ação `Query` não seria suficiente para responder a essas perguntas. Em vez disso, você teria de `Scan` toda a tabela. Para uma tabela com milhões de itens, isso poderia consumir uma grande quantidade de throughput provisionado de leitura e levar muito tempo para ser concluído.

No entanto, é possível especificar um ou mais índices secundários em atributos que não são chaves, como `Replies` ou `LastPostDateTime`.

Um *índice secundário local* mantém uma chave de classificação alternativa para um determinado valor de chave de partição. Um índice secundário local também contém uma cópia de alguns ou de todos os atributos de sua tabela-base. Você especifica quais atributos são projetados no índice secundário local ao criar a tabela. Os dados em um índice secundário local são organizados com a mesma chave de partição que a tabela-base, mas com outra chave de classificação. Isso permite que você acesse os itens de dados de forma eficiente nessa dimensão diferente. Para uma maior flexibilidade de consulta ou verificação, você pode criar até cinco índices secundários locais por tabela. 

Suponha que um aplicativo precise encontrar todos os threads que foram publicados nos últimos três meses em um fórum específico. Sem um índice secundário local, a aplicação precisaria realizar `Scan` de toda a tabela `Thread` e descartar todas as publicações que não estivessem dentro do período especificado. Com um índice secundário local, uma operação de `Query` poderia usar `LastPostDateTime` como uma chave de classificação e encontrar os dados rapidamente.

O diagrama a seguir mostra um índice secundário local chamado `LastPostIndex`. Observe que a chave de partição é a mesma que a da tabela `Thread`, mas a chave de classificação é `LastPostDateTime`.

![\[A tabela LastPostIndex que contém uma lista de nomes, assuntos e a hora da última publicação do fórum.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/LSI_02.png)


Cada índice secundário local deve atender às seguintes condições:
+ A chave de partição é a mesma que a de sua tabela-base.
+ A chave de classificação consiste em exatamente um atributo escalar.
+ A chave de classificação da tabela-base é projetada no índice, onde ela atua como um atributo que não é chave.

Neste exemplo, a chave de partição é `ForumName` e a chave de classificação do índice secundário local é `LastPostDateTime`. Além disso, o valor da chave de classificação da tabela base (neste exemplo, `Subject`) é projetado no índice, mas não faz parte da chave do índice. Se um aplicativo precisar de uma lista baseada em `ForumName` e `LastPostDateTime`, ele poderá emitir uma solicitação de `Query` com relação a `LastPostIndex`. Os resultados da consulta são classificados por `LastPostDateTime` e podem ser retornados em ordem crescente ou decrescente. A consulta também pode aplicar condições de chave, como retornar apenas os itens que têm uma `LastPostDateTime` dentro de um período específico.

Cada índice secundário local contém automaticamente as chave de partição e de classificação de sua tabela-base, mas você pode opcionalmente projetar atributos não chave no índice. Quando você consultar o índice, o DynamoDB poderá recuperar esses atributos projetados com eficiência. Quando você consulta um índice secundário local, a consulta também pode recuperar atributos que *não* são projetados no índice. O DynamoDB buscará automaticamente esses atributos na tabela-base, mas com uma latência maior e com custos de throughput provisionado mais altos.

Para qualquer índice secundário local, você pode armazenar até 10 GB de dados por valor de chave de partição distinta. Esta imagem inclui todos os itens na tabela-base, além de todos os itens nos índices, que têm o mesmo valor de chave de partição. Para obter mais informações, consulte [Conjuntos de itens em índices secundários locais](#LSI.ItemCollections).

## Projeções de atributo
<a name="LSI.Projections"></a>

Com `LastPostIndex`, um aplicativo poderia usar `ForumName` e `LastPostDateTime` como critérios de consulta. No entanto, para recuperar qualquer atributo adicional, o DynamoDB deve executar operações de leitura adicionais na tabela `Thread`. Essas leituras extras são conhecidas como *buscas* e podem aumentar a quantidade total de throughput provisionado necessário para uma consulta.

Suponha que você quisesse preencher uma página da Web com uma lista de todos os threads de "S3" e o número de respostas para cada thread, classificados pela última data/hora de resposta, começando pela resposta mais recente. Para preencher essa lista, você precisaria dos seguintes atributos:
+ `Subject`
+ `Replies`
+ `LastPostDateTime`

A maneira mais eficiente de consultar esses dados e evitar operações de busca seria projetar o atributo `Replies` da tabela no índice secundário local conforme mostrado neste diagrama.

![\[A tabela LastPostIndex que contém uma lista de nomes, datas das últimas publicações, assuntos e respostas do fórum.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/LSI_03.png)




Uma *projeção* é o conjunto de atributos que é copiado de uma tabela para um índice secundário. A chave de partição e a chave de classificação da tabela são sempre projetadas no índice; você pode projetar outros atributos para suportar os requisitos de consulta da sua aplicação. Quando você consulta um índice, o Amazon DynamoDB pode acessar quaisquer atributos na projeção como se estivessem em uma tabela própria.

Quando você cria um índice secundário, é necessário especificar os atributos que serão projetados no índice. O DynamoDB proporciona três opções diferentes para fazer isso:
+ *KEYS\$1ONLY*: cada item do índice consiste apenas nos valores de chaves de partição e nas chaves de classificação da tabela, além dos valores de chaves do índice. A opção `KEYS_ONLY` resulta no menor índice secundário possível.
+ *INCLUDE*: além dos atributos descritos em `KEYS_ONLY`, o índice secundário incluirá outros atributos não chave que você especificar.
+ *ALL*: o índice secundário inclui todos os atributos da tabela de origem. Como todos os dados da tabela são duplicados no índice, uma projeção `ALL` resulta no maior índice secundário possível.

No diagrama anterior, o atributo `Replies` que não é chave é projetado em `LastPostIndex`. Um aplicativo pode consultar `LastPostIndex` em vez da tabela `Thread` completa para preencher uma página da Web com `Subject`, `Replies` e `LastPostDateTime`. Se quaisquer outros atributos que não são chaves forem solicitados, o DynamoDB precisará buscar esses atributos na tabela `Thread`. 

Do ponto de vista de um aplicativo, buscar atributos adicionais da tabela-base é automático e transparente, portanto, não há necessidade de reescrever qualquer lógica de aplicativo. No entanto, essa busca pode reduzir significativamente a vantagem de performance proporcionada pelo uso de um índice secundário local.

Ao escolher os atributos para projetar em um índice secundário local, você deve considerar a desvantagem entre os custos de throughput provisionado e os custos de armazenamento:
+ Se você precisar acessar apenas alguns atributos com a latência mais baixa possível, considere projetar apenas os atributos em um índice secundário local. Quanto menor o índice, menores serão os custos de armazenamento e de gravação. Se houver atributos que você precisa buscar ocasionalmente, o custo de throughput provisionado pode ultrapassar o custo por um prazo mais longo do armazenamento desses atributos.
+ Se sua aplicação acessar frequentemente alguns atributos não chave, considere projetar esses atributos em um índice secundário local. Os custos adicionais de armazenamento do índice secundário local compensarão o custo de executar verificações de tabelas frequentes.
+ Se precisar acessar a maioria dos atributos não chave com frequência, você poderá projetar esses atributos, inclusive a tabela-base inteira, em um índice secundário local. Isso fornece flexibilidade máxima e menor consumo de throughput provisionado, porque nenhuma busca será necessária. No entanto, o custo do armazenamento deve aumentar ou até dobrar se você estiver projetando todos os atributos.
+ Se o seu aplicativo precisa consultar uma tabela com pouca frequência, mas deve realizar muitas gravações ou atualizações nos dados na tabela, pense em projetar *KEYS\$1ONLY*. O índice secundário local seria de tamanho mínimo, mas ainda estaria disponível quando necessário para a atividade de consulta. 

## Criação de um índice secundário local
<a name="LSI.Creating"></a>

Para criar um ou mais índices secundários locais, use o parâmetro `LocalSecondaryIndexes` da operação `CreateTable`. Os índices secundários locais em uma tabela são criados quando a tabela é criada. Quando você exclui uma tabela, todos os índices secundários locais da tabela também são excluídos.

Você deve especificar um atributo não chave para atuar como a chave de classificação do índice secundário local. O atributo escolhido deve ser de um tipo escalar como `String`, `Number` ou `Binary` Outros tipos escalares, tipos de documento e tipos de conjunto não são permitidos. Para obter uma lista completa de tipos de dados, consulte [Tipos de dados](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes).

**Importante**  
Para tabelas com índices secundários locais, há um limite de tamanho de 10 GB para cada valor de chave de partição. Uma tabela com índices secundários locais pode armazenar qualquer número de itens, desde que o tamanho total de qualquer valor de chave de partição não exceda 10 GB. Para obter mais informações, consulte [Limite de tamanho de conjunto de itens](#LSI.ItemCollections.SizeLimit).

Você pode projetar atributos de qualquer tipo de dados em um índice secundário local. Isso inclui escalares, documentos e conjuntos. Para obter uma lista completa de tipos de dados, consulte [Tipos de dados](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes).

## Ler dados de um índice secundário local
<a name="LSI.Reading"></a>

Você pode recuperar itens de um índice secundário local usando as operações `Query` e `Scan`. As operações `GetItem` e `BatchGetItem` não podem ser usadas em um índice secundário local.

### Como consultar um índice secundário local
<a name="LSI.Querying"></a>

Em uma tabela do DynamoDB, o valor da chave de partição combinada e o valor da chave de classificação de cada item devem ser exclusivos. No entanto, em um índice secundário local, o valor da chave de classificação não precisa ser exclusivo para um determinado valor de chave de partição. Se houver vários itens no índice secundário local com o mesmo valor de chave de classificação, uma operação `Query` retornará todos os itens que têm o mesmo valor de chave de partição. Na resposta, os itens correspondentes não são retornados em uma ordem específica.

Você pode consultar um índice secundário local usando leituras fortemente consistentes ou finais consistentes. Para especificar qual tipo de consistência você deseja, use o parâmetro `ConsistentRead` da operação `Query`. Uma leitura fortemente consistente de um índice secundário local sempre retorna os valores atualizados mais recentes. Se a consulta precisar buscar atributos adicionais na tabela base, esses atributos serão consistentes com relação ao índice.

**Example**  
Considere os seguintes dados retornados de uma `Query` que solicita dados dos threads de discussão em um determinado fórum.  

```
{
    "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"}
    }
}
```
Nesta consulta:  
+ O DynamoDB acessa `LastPostIndex` usando a chave de partição `ForumName` para localizar os itens do índice para o "EC2". Todos os itens do índice com essa chave são armazenados lado a lado para rápida recuperação.
+ Neste fórum, o DynamoDB usa o índice para pesquisar as chaves que correspondem à condição `LastPostDateTime` especificada.
+ Como o atributo `Replies` é projetado no índice, o DynamoDB pode recuperar esse atributo sem consumir nenhum throughput provisionado adicional.
+ O atributo `Tags` não é projetado no índice, portanto, o DynamoDB deve acessar a tabela `Thread` e buscar esse atributo.
+ Os resultados são retornados, classificados por `LastPostDateTime`. As entradas de índice são classificadas por valor de chave de partição e, em seguida, pelo valor de chave de classificação, e `Query` retorna-as na ordem em que são armazenadas. (Você pode usar o parâmetro `ScanIndexForward` para retornar os resultados em ordem decrescente.)
Como o atributo `Tags` não é projetado no índice secundário local, o DynamoDB deve consumir unidades de capacidade de leitura adicionais para buscar esse atributo na tabela-base. Se for necessário executar essa consulta com frequência, projete `Tags` no `LastPostIndex` para evitar a busca na tabela base. No entanto, se for necessário acessar `Tags` apenas ocasionalmente, o custo do armazenamento adicional para a projeção de `Tags` no índice pode não valer a pena.

### Verificação de um índice secundário local
<a name="LSI.Scanning"></a>

Você pode usar `Scan` para recuperar todos os dados de um índice secundário local. Você deve fornecer o nome da tabela-base e o nome de índice na solicitação. Com uma operação `Scan`, o DynamoDB lê todos os dados do índice e os retorna para a aplicação. Você também pode solicitar que apenas alguns dos dados sejam retornados, e que os dados restantes sejam descartados. Para fazer isso, use o parâmetro `FilterExpression` da API `Scan`. Para obter mais informações, consulte [Expressões de filtro para verificação](Scan.md#Scan.FilterExpression).

## Gravações de itens e índices secundários locais
<a name="LSI.Writes"></a>

O DynamoDB mantém automaticamente todos os índices secundários locais sincronizados com suas respectivas tabelas base. Os aplicativos nunca gravam diretamente em um índice. No entanto, é importante compreender as implicações de como o DynamoDB mantém esses índices.

Ao criar um índice secundário local, você especifica um atributo para servir como a chave de classificação do índice. Você também especifica um tipo de dados desse atributo. Isso significa que sempre que você grava um item na tabela-base, se o item define um atributo de chave do índice, seu tipo deve corresponder ao tipo de dados do esquema de chaves do índice. No caso de `LastPostIndex`, a chave de classificação de `LastPostDateTime` no índice é definida como um tipo de dados `String`. Se você tentar adicionar um item à tabela `Thread` e especificar um tipo de dados diferente para `LastPostDateTime` (como `Number`), o DynamoDB retornará uma `ValidationException` devido à inconsistência do tipo de dados.

Não há necessidade de um relacionamento de um para um entre os itens em uma tabela-base e os itens em um índice secundário local. Na verdade, esse comportamento pode ser vantajoso para muitas aplicações. 

Os custos das atividades de gravação em uma tabela com muitos índices secundários serão mais altos do que em uma tabela com um número menor de índices. Para obter mais informações, consulte [Considerações sobre throughput provisionado para índices secundários locais](#LSI.ThroughputConsiderations).

**Importante**  
Para tabelas com índices secundários locais, há um limite de tamanho de 10 GB para cada valor de chave de partição. Uma tabela com índices secundários locais pode armazenar qualquer número de itens, desde que o tamanho total de qualquer valor de chave de partição não exceda 10 GB. Para obter mais informações, consulte [Limite de tamanho de conjunto de itens](#LSI.ItemCollections.SizeLimit).

## Considerações sobre throughput provisionado para índices secundários locais
<a name="LSI.ThroughputConsiderations"></a>

Ao criar uma tabela no DynamoDB, você provisiona unidades de capacidade de leitura e gravação para a workload esperada na tabela. Essa workload inclui a atividade de leitura e gravação nos índices secundários locais da tabela.

Para visualizar as taxas atuais da capacidade de throughput provisionado, acesse [Preços do Amazon DynamoDB](https://aws.amazon.com/dynamodb/pricing).

### Unidades de capacidade de leitura
<a name="LSI.ThroughputConsiderations.Reads"></a>

Quando você consulta um índice secundário local, o número de unidades de capacidade de leitura consumidas depende de como os dados são acessados.

Assim como ocorre com as consultas de tabela, uma consulta de índice pode usar leituras fortemente consistentes ou eventualmente consistentes, dependendo do valor de `ConsistentRead`. Uma leitura fortemente consistente consome uma unidade de capacidade de leitura, uma leitura eventualmente consistente consome apenas metade disso. Assim, escolhendo leituras eventualmente consistentes, você pode reduzir seus encargos de unidade de capacidade de leitura.

Para consultas do índice que solicitam apenas chaves de índice e atributos projetados, o DynamoDB calcula a atividade de leitura provisionada da mesma forma que para consultas em tabelas. A única diferença é que o cálculo é baseado no tamanho das entradas de índice, em vez do tamanho do item na tabela-base. O número de unidades de capacidade de leitura é a soma de todos os tamanhos de atributos projetados em todos os itens retornados; o resultado é, então, arredondado para o próximo limite de 4 KB. Para obter mais informações sobre como o DynamoDB calcula a utilização de throughput provisionado, consulte [Modo de capacidade provisionada do DynamoDB](provisioned-capacity-mode.md).

Para consultas de índice que leem atributos que não estão projetados no índice secundário local, o DynamoDB precisa buscar esses atributos na tabela-base, além de ler os atributos projetados no índice. Essas buscas ocorrem quando você inclui quaisquer atributos não projetados nos parâmetros `Select` ou `ProjectionExpression` da operação `Query`. A busca causa latência adicional nas respostas da consulta, e também incorre em um custo mais alto de throughput provisionado: além das leituras do índice secundário local descritas acima, você é cobrado pelas unidades de capacidade de leitura de cada item buscado na tabela-base. Essa cobrança é para ler cada item inteiro da tabela, não apenas os atributos solicitados.

O tamanho máximo dos resultados retornados por uma operação `Query` é 1 MB. Isso inclui os tamanhos de todos os nomes e valores de atributos de todos os itens retornados. No entanto, se uma consulta em um índice secundário local fizer o DynamoDB buscar atributos de item na tabela-base, o tamanho máximo dos dados no resultado poderá ser menor. Neste caso, o tamanho do resultado é a soma de:
+ O tamanho dos itens correspondentes no índice, arredondado para os próximos 4 KB.
+ O tamanho de cada item correspondente na tabela-base, com cada item individualmente arredondado para os próximos 4 KB.

Usando esta fórmula, o tamanho máximo dos resultados retornados por uma operação Query ainda é 1 MB.

Por exemplo, considere uma tabela na qual o tamanho de cada item é 300 bytes. Há um índice secundário local nessa tabela, mas apenas 200 bytes de cada item são projetados no índice. Agora, suponha que você use a operação `Query` nesse índice, que a consulta requer buscas de tabela para cada item e que a consulta retorne 4 itens. O DynamoDB soma o seguinte:
+ O tamanho dos itens correspondentes no índice: 200 bytes × 4 itens = 800 bytes; isso é, então, arredondado para 4 KB.
+ O tamanho de cada item correspondente na tabela-base: (300 bytes, arredondados para 4 KB) × 4 itens = 16 KB.

O tamanho total dos dados no resultado é, portanto, 20 KB.

### Unidades de capacidade de gravação
<a name="LSI.ThroughputConsiderations.Writes"></a>

Quando um item é adicionado, atualizado ou excluído de uma tabela, a atualização dos índices secundários locais consome unidades de capacidade de gravação provisionadas para a tabela. O custo total do throughput provisionado para uma gravação é a soma das unidades de capacidade de gravação consumidas pela gravação na tabela e aquelas consumidas pela atualização dos índices secundários locais.

O custo de gravar um item em um índice secundário local depende de vários fatores:
+ Se você gravar um novo item na tabela que define um atributo indexado, ou atualizar um item existente para definir um atributo indexado indefinido anteriormente, uma operação de gravação é necessária para inserir o item no índice.
+ Se uma atualização na tabela alterar o valor de um atributo de chave indexado (de A para B), duas gravações serão necessárias, uma para excluir o item anterior do índice e outra gravação para inserir o novo item no índice.  
+ Se um item estava presente no índice, mas uma gravação na tabela fez com que o atributo indexado fosse excluído, uma gravação é necessária para excluir a projeção do item antigo do índice.
+ Se um item não estiver presente no índice antes ou depois que o item é atualizado, não haverá custo de gravação adicionais para o índice.

Todos esses fatores supõem que o tamanho de cada item no índice seja menor ou igual ao tamanho de item de 1 KB para calcular unidades de capacidade de gravação. Entradas de índice maiores exigirão unidades adicionais de capacidade de gravação. Você pode minimizar os custos de gravação considerando de quais atributos suas consultas precisam para retornar e projetar apenas esses atributos no índice.

## Considerações sobre armazenamento para índices secundários locais
<a name="LSI.StorageConsiderations"></a>

Quando uma aplicação grava um item em uma tabela, o DynamoDB copia automaticamente o subconjunto correto de atributos em todos os índices secundários locais nos quais esses atributos devem aparecer. Sua conta da AWS é cobrada pelo armazenamento do item na tabela-base e também pelo armazenamento dos atributos em todos os índices secundários locais nessa tabela.

A quantidade de espaço usada por um item do índice é a soma do seguinte:
+ O tamanho em bytes da chave primária da tabela-base (chave de partição e chave de classificação)
+ O tamanho em bytes do atributo de chave do índice
+ O tamanho em bytes dos atributos projetados (se houver)
+ 100 bytes de sobrecarga por item de índice

Para estimar os requisitos de armazenamento de um índice secundário local, você pode estimar o tamanho médio de um item no índice e multiplicar pelo número de itens no índice.

Se uma tabela contiver um item em que um determinado atributo não está definido, mas esse atributo estiver definido como uma chave de classificação do índice, o DynamoDB não gravará nenhum dado desse item no índice. 

## Conjuntos de itens em índices secundários locais
<a name="LSI.ItemCollections"></a>

**nota**  
A seção refere-se apenas a tabelas que têm índices secundários locais.

No DynamoDB, uma *coleção de itens* é qualquer grupo de itens que têm o mesmo valor de chave de partição em uma tabela e todos os seus índices secundários locais. Nos exemplos usados nesta seção, a chave de partição da tabela `Thread` é `ForumName`, e a chave de partição de `LastPostIndex` também é `ForumName`. Todos os itens da tabela e do índice com o mesmo `ForumName` fazem parte da mesma coleção de itens. Por exemplo, na tabela `Thread` e no índice secundário local `LastPostIndex`, existe uma coleção de itens para o fórum do `EC2` e uma coleção de itens diferente para o fórum do `RDS`.

O seguinte diagrama mostra a coleção de itens do fórum do `S3`.

![\[Uma coleção de itens do DynamoDB com itens de tabela e de índice secundário local que têm o mesmo valor de chave de partição de S3.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/LSI_04.png)


Neste diagrama, a coleção de itens consiste em todos os itens em `Thread` e `LastPostIndex` em que o valor da chave da partição `ForumName` é "S3". Se houver outros índices secundários locais na tabela, todos os itens nesses índices com `ForumName` igual a "S3" também farão parte da coleção de itens.

Você pode usar qualquer uma das operações a seguir no DynamoDB para retornar informações sobre coleções de itens:
+ `BatchWriteItem`
+ `DeleteItem`
+ `PutItem`
+ `UpdateItem`
+ `TransactWriteItems`

Cada uma dessas operações é compatível com o parâmetro `ReturnItemCollectionMetrics`. Ao definir esse parâmetro como `SIZE`, você pode exibir informações sobre o tamanho de cada coleção de itens no índice.

**Example**  
Este é um exemplo da saída de uma operação `UpdateItem` na tabela `Thread`, com `ReturnItemCollectionMetrics` definido como `SIZE`. O item que foi atualizado tinha um valor `ForumName` de "EC2", portanto, a saída inclui informações sobre essa coleção de itens.  

```
{
    ItemCollectionMetrics: {
        ItemCollectionKey: {
            ForumName: "EC2"
        },
        SizeEstimateRangeGB: [0.0, 1.0]
    }
}
```
O objeto `SizeEstimateRangeGB` mostra que o tamanho dessa coleção de itens está entre 0 e 1 GB. O DynamoDB atualiza periodicamente essa estimativa de tamanho, portanto, os números podem ser diferentes na próxima vez em que o item é modificado.

### Limite de tamanho de conjunto de itens
<a name="LSI.ItemCollections.SizeLimit"></a>

O tamanho máximo de qualquer coleção de itens para uma tabela com um ou mais índices secundários locais é 10 GB. Isso não se aplica a coleções de itens em tabelas sem índices secundários locais e também não se aplica a coleções de itens em índices secundários globais. Apenas as tabelas que têm um ou mais índices secundários locais são afetadas.

Se uma coleção de itens exceder o limite de 10 GB, o DynamoDB pode retornar um `ItemCollectionSizeLimitExceededException`, e você não poderá adicionar mais itens à coleção de itens ou aumentar os tamanhos dos itens que estão na coleção de itens. (As operações de leitura e gravação que diminuem o tamanho da coleção de itens ainda são permitidas.) Você ainda pode adicionar itens a outras coleções de itens.

Para reduzir o tamanho de uma coleção de itens, você pode executar uma das seguintes ações:
+ Excluir todos os itens desnecessários com o valor da chave de partição em questão. Quando você exclui esses itens da tabela-base, o DynamoDB também remove todas as entradas do índice que têm o mesmo valor de chave de partição.
+ Atualize os itens, removendo atributos ou reduzindo o tamanho dos atributos. Se esses atributos forem projetados em qualquer índice secundário local, o DynamoDB também reduzirá o tamanho das entradas do índice correspondentes.
+ Crie uma nova tabela com a mesma chave de partição e chave de classificação e, em seguida, mova os itens da tabela antiga para a nova tabela. Essa pode ser uma boa abordagem, se uma tabela tiver dados históricos que são acessados com pouca frequência. Você também pode considerar arquivar esses dados históricos no Amazon Simple Storage Service (Amazon S3).

Quando o tamanho total da coleção de itens tornar-se inferior a 10 GB, você poderá adicionar itens novamente com o mesmo valor de chave de partição.

Recomendamos como uma melhor prática que você instrumente seu aplicativo para monitorar os tamanhos de suas coleções de itens. Uma maneira de fazer isso é definir o parâmetro `ReturnItemCollectionMetrics` como `SIZE` sempre que você usar `BatchWriteItem`, `DeleteItem`, `PutItem` ou `UpdateItem`. Seu aplicativo deve examinar o objeto `ReturnItemCollectionMetrics` na saída e gerar uma mensagem de erro sempre que uma coleção de itens exceder um limite definido pelo usuário (por exemplo, 8 GB). Configurar um limite menor que 10 GB oferece um sistema de aviso antecipado para que você saiba que uma coleção de itens está se aproximando do limite a tempo de resolver o problema.

### Conjuntos de itens e partições
<a name="LSI.ItemCollections.OnePartition"></a>

Em uma tabela com um ou mais índices secundários locais, uma coleção de itens é armazenada em uma partição. O tamanho total dessa coleção de itens é limitado à capacidade dessa partição: 10 GB. Para uma aplicação em que o modelo de dados inclui coleções de itens de tamanho ilimitado ou na qual a expectativa é de que algumas coleções de itens aumentem além de 10 GB no futuro, pense em usar um índice secundário global.

Você deve criar seus aplicativos para que os dados da tabela sejam distribuídos uniformemente entre diferentes valores de chave de partição. Para tabelas com índices secundários locais, seus aplicativos não devem criar pontos de atividade de leitura e gravação em uma única coleção de itens em uma única partição. 

# Como trabalhar com índices secundários locais: Java
<a name="LSIJavaDocumentAPI"></a>

Você pode usar a API de documentos do AWS SDK para Java para criar uma tabela do Amazon DynamoDB com um ou mais índices secundários locais na tabela e executar consultas usando os índices.

Veja a seguir as etapas comuns para operações de tabela usando a API de documento do AWS SDK para Java.

1. Crie uma instância da classe `DynamoDB`.

1. Forneça os parâmetros obrigatórios e opcionais para a operação, criando os objetos de solicitação correspondentes. 

1. Chame o método apropriado fornecido pelo cliente que você criou na etapa anterior. 

**Topics**
+ [Criar uma tabela com um índice secundário local](#LSIJavaDocumentAPI.CreateTableWithIndex)
+ [Descrever uma tabela com um índice secundário local](#LSIJavaDocumentAPI.DescribeTableWithIndex)
+ [Consultar um índice secundário local](#LSIJavaDocumentAPI.QueryAnIndex)
+ [Exemplo: índices secundários locais que usam a API de documentos do Java](LSIJavaDocumentAPI.Example.md)

## Criar uma tabela com um índice secundário local
<a name="LSIJavaDocumentAPI.CreateTableWithIndex"></a>

Os índices secundários locais devem ser criados ao mesmo tempo que uma tabela é criada. Para fazer isso, use o método `createTable` e forneça suas especificações para um ou mais índices secundários locais. O exemplo de código Java a seguir cria uma tabela para armazenar informações sobre músicas em uma coleção de músicas. A chave de partição é `Artist` e a chave de classificação é `SongTitle`. Um índice secundário, `AlbumTitleIndex`, facilita consultas por título de álbum. 

Veja a seguir as etapas necessárias para criar uma tabela com um índice secundário local usando a API de documentos do DynamoDB. 

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `CreateTableRequest` para fornecer as informações solicitadas. 

   Você deve fornecer o nome da tabela, sua chave primária e os valores de throughput provisionado. Para o índice secundário local, você deve fornecer o nome do índice, o nome e o tipo de dados da chave de classificação do índice, o esquema de chave para o índice e a projeção de atributos.

1. Chame o método `createTable`, fornecendo o objeto de solicitação como um parâmetro.

O exemplo de código Java a seguir demonstra as etapas anteriores. O código cria uma tabela (`Music`) com um índice secundário no atributo `AlbumTitle`. A chave de partição de tabela e a chave de classificação, bem como a chave de classificação de índice, são os únicos atributos projetados para o índice.

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

Você deve aguardar até que o DynamoDB crie a tabela e defina o status dessa tabela como `ACTIVE`. Depois disso, você poderá começar a inserir itens de dados na tabela.

## Descrever uma tabela com um índice secundário local
<a name="LSIJavaDocumentAPI.DescribeTableWithIndex"></a>

Para obter mais informações sobre índices secundários locais em uma tabela, use o método `describeTable`. Para cada índice, você pode acessar seu nome, esquema de chaves e atributos projetados.

Veja a seguir as etapas para acessar informações do índice secundário local de uma tabela usando a API de documento do AWS SDK para Java.

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `Table`. Você deve fornecer o nome da tabela.

1. Chame o método `describeTable` no objeto `Table`.

O exemplo de código Java a seguir demonstra as etapas anteriores.

**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());
    }
}
```

## Consultar um índice secundário local
<a name="LSIJavaDocumentAPI.QueryAnIndex"></a>

Você pode usar a operação `Query` em um índice secundário local de forma semelhante ao uso de `Query` em uma tabela. Você deve especificar o nome do índice, os critérios de consulta da chave de classificação do índice e os atributos que deseja retornar. Neste exemplo, o índice é `AlbumTitleIndex` e a chave de classificação do índice é `AlbumTitle`. 

Os únicos atributos retornados são aqueles que foram projetados no índice. É possível modificar essa consulta para selecionar atributos não chave também, mas isso exigiria atividades de busca de tabela que são relativamente caras. Para obter mais informações sobre buscas de tabela, consulte [Projeções de atributo](LSI.md#LSI.Projections).

Veja a seguir as etapas para consultar um índice secundário local usando a API de documento do AWS SDK para Java. 

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `Table`. Você deve fornecer o nome da tabela.

1. Crie uma instância da classe `Index`. Você deve fornecer o nome do índice.

1. Chame o método `query` da classe `Index`.

O exemplo de código Java a seguir demonstra as etapas anteriores.

**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());
}
```

### Leituras consistentes em um índice secundário local
<a name="LSIJavaDocumentAPI.ConsistentReads"></a>

Ao contrário dos índices secundários globais, que permitem leituras finais consistentes, o índice secundário local permite leituras altamente consistentes. Uma leitura fortemente consistente de um índice secundário local sempre retorna os valores atualizados mais recentes. Se a consulta precisar buscar atributos adicionais na tabela base, esses atributos também serão consistentes com relação ao índice.

Por padrão, `Query` usa leituras finais consistentes. Para solicitar uma leitura altamente consistente, defina `ConsistentRead` como `true` em `QuerySpec`. O exemplo a seguir consulta `AlbumTitleIndex` usando uma leitura altamente consistente:

**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);
```

**nota**  
Uma leitura altamente consistente consome 1 unidade de capacidade de leitura por 4 KB de dados exibidos (arredondados para cima), enquanto uma leitura final consistente consome metade disso. Por exemplo, uma leitura altamente consistente que exibe 9 KB de dados consome 3 unidades de capacidade de leitura (9 KB/4 KB = 2,25, arredondado para 3), enquanto a mesma consulta usando uma leitura final consistente consome 1,5 unidade de capacidade de leitura. Se sua aplicação admitir a leitura de dados que possam estar um pouco obsoletos, use leituras finais consistentes para reduzir o uso da capacidade de leitura. Para obter mais informações, consulte [Unidades de capacidade de leitura](LSI.md#LSI.ThroughputConsiderations.Reads).

# Exemplo: índices secundários locais que usam a API de documentos do Java
<a name="LSIJavaDocumentAPI.Example"></a>

O exemplo de código Java a seguir mostra como trabalhar com índices secundários locais no Amazon DynamoDB. O exemplo cria uma tabela chamada `CustomerOrders` com uma chave de partição `CustomerId` e uma chave de classificação `OrderId`. Há dois índices secundários locais nessa tabela:
+ `OrderCreationDateIndex`: a chave de classificação é `OrderCreationDate`, e os seguintes atributos são projetados no índice:
  + `ProductCategory`
  + `ProductName`
  + `OrderStatus`
  + `ShipmentTrackingId`
+ `IsOpenIndex`: a chave de classificação é `IsOpen`, e todos os atributos da tabela estão projetados no índice.

Depois que a tabela `CustomerOrders` é criada, o programa carrega a tabela com os dados que representam pedidos de clientes. Ele então consulta os dados usando os índices secundários globais. Por fim, o programa exclui a tabela `CustomerOrders`.

Para obter instruções detalhadas sobre como testar o exemplo a seguir, consulte [Exemplos de código 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());
    }
}
```

# Como trabalhar com índices secundários locais: .NET
<a name="LSILowLevelDotNet"></a>

**Topics**
+ [Criar uma tabela com um índice secundário local](#LSILowLevelDotNet.CreateTableWithIndex)
+ [Descrever uma tabela com um índice secundário local](#LSILowLevelDotNet.DescribeTableWithIndex)
+ [Consultar um índice secundário local](#LSILowLevelDotNet.QueryAnIndex)
+ [Exemplo: índices secundários locais que usam a API de baixo nível do AWS SDK para .NET](LSILowLevelDotNet.Example.md)

Você pode usar a API de baixo nível do AWS SDK para .NET para criar uma tabela do Amazon DynamoDB com um ou mais índices secundários locais na tabela e executar consultas usando os índices. Essas operações são mapeadas nas ações correspondentes da API de baixo nível do DynamoDB. Para obter mais informações, consulte [Exemplos de código .NET](CodeSamples.DotNet.md). 

Veja a seguir as etapas comuns para operações de tabela usando a API de baixo nível do .NET. 

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Forneça os parâmetros obrigatórios e opcionais para a operação, criando os objetos de solicitação correspondentes.

   Por exemplo, crie um objeto `CreateTableRequest` para criar uma tabela e crie um objeto `QueryRequest` para consultar uma tabela ou um índice. 

1. Execute o método apropriado fornecido pelo cliente que você criou na etapa anterior. 

## Criar uma tabela com um índice secundário local
<a name="LSILowLevelDotNet.CreateTableWithIndex"></a>

Os índices secundários locais devem ser criados ao mesmo tempo que uma tabela é criada. Para fazer isso, use `CreateTable` e forneça suas especificações para um ou mais índices secundários locais. O exemplo de código C\$1 a seguir cria uma tabela para armazenar informações sobre músicas em uma coleção de músicas. A chave de partição é `Artist` e a chave de classificação é `SongTitle`. Um índice secundário, `AlbumTitleIndex`, facilita consultas por título de álbum. 

Veja a seguir as etapas necessárias para criar uma tabela com um índice secundário local usando a API de baixo nível do .NET. 

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Crie uma instância da classe `CreateTableRequest` para fornecer as informações solicitadas. 

   Você deve fornecer o nome da tabela, sua chave primária e os valores de throughput provisionado. Para o índice secundário local, você deve fornecer o nome do índice, o nome e o tipo de dados da chave de classificação do índice, o esquema de chave para o índice e a projeção de atributos.

1. Execute o método `CreateTable` fornecendo o objeto de solicitação como um parâmetro.

O exemplo de código C\$1 a seguir demonstra as etapas anteriores. O código cria uma tabela (`Music`) com um índice secundário no atributo `AlbumTitle`. A chave de partição de tabela e a chave de classificação, bem como a chave de classificação de índice, são os únicos atributos projetados para o índice.

```
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);
```

Você deve aguardar até que o DynamoDB crie a tabela e defina o status dessa tabela como `ACTIVE`. Depois disso, você poderá começar a inserir itens de dados na tabela.

## Descrever uma tabela com um índice secundário local
<a name="LSILowLevelDotNet.DescribeTableWithIndex"></a>

Para obter mais informações sobre índices secundários locais em uma tabela, use a API `DescribeTable`. Para cada índice, você pode acessar seu nome, esquema de chaves e atributos projetados.

Veja a seguir as etapas para acessar informações do índice secundário local para uma tabela usando a API de baixo nível do .NET. 

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Crie uma instância da classe `DescribeTableRequest` para fornecer as informações solicitadas. Você deve fornecer o nome da tabela.

1. Execute o método `describeTable` fornecendo o objeto de solicitação como um parâmetro.

O exemplo de código C\$1 a seguir demonstra as etapas anteriores.

**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);
        }

    }
}
```

## Consultar um índice secundário local
<a name="LSILowLevelDotNet.QueryAnIndex"></a>

Você pode usar `Query` em um índice secundário local de forma semelhante ao uso de `Query` em uma tabela. Você deve especificar o nome do índice, os critérios de consulta da chave de classificação do índice e os atributos que deseja retornar. Neste exemplo, o índice é `AlbumTitleIndex` e a chave de classificação do índice é `AlbumTitle`. 

Os únicos atributos retornados são aqueles que foram projetados no índice. É possível modificar essa consulta para selecionar atributos não chave também, mas isso exigiria atividades de busca de tabela que são relativamente caras. Para obter mais informações sobre buscas de tabela, consulte [Projeções de atributo](LSI.md#LSI.Projections)

Veja a seguir as etapas para consultar um índice secundário local usando a API de baixo nível do .NET. 

1. Crie uma instância da classe `AmazonDynamoDBClient`.

1. Crie uma instância da classe `QueryRequest` para fornecer as informações solicitadas.

1. Execute o método `query` fornecendo o objeto de solicitação como um parâmetro.

O exemplo de código C\$1 a seguir demonstra as etapas anteriores.

**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();
}
```

# Exemplo: índices secundários locais que usam a API de baixo nível do AWS SDK para .NET
<a name="LSILowLevelDotNet.Example"></a>

O exemplo de código C\$1 a seguir mostra como trabalhar com índices secundários locais no Amazon DynamoDB. O exemplo cria uma tabela chamada `CustomerOrders` com uma chave de partição `CustomerId` e uma chave de classificação `OrderId`. Há dois índices secundários locais nessa tabela:
+ `OrderCreationDateIndex`: a chave de classificação é `OrderCreationDate`, e os seguintes atributos são projetados no índice:
  + `ProductCategory`
  + `ProductName`
  + `OrderStatus`
  + `ShipmentTrackingId`
+ `IsOpenIndex`: a chave de classificação é `IsOpen`, e todos os atributos da tabela estão projetados no índice.

Depois que a tabela `CustomerOrders` é criada, o programa carrega a tabela com os dados que representam pedidos de clientes. Ele então consulta os dados usando os índices secundários globais. Por fim, o programa exclui a tabela `CustomerOrders`.

Para obter instruções passo a passo sobre como testar o exemplo a seguir, consulte [Exemplos de código .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;
                }
            }
        }
    }
}
```

# Trabalhar com índices secundários locais no DynamoDB usando a AWS CLI
<a name="LCICli"></a>

Você pode usar a AWS CLI para criar uma tabela do Amazon DynamoDB com um ou mais índices secundários locais, descrever os índices na tabela e realizar consultas usando os índices.

**Topics**
+ [Criar uma tabela com um índice secundário local](#LCICli.CreateTableWithIndex)
+ [Descrever uma tabela com um índice secundário local](#LCICli.DescribeTableWithIndex)
+ [Consultar um índice secundário local](#LCICli.QueryAnIndex)

## Criar uma tabela com um índice secundário local
<a name="LCICli.CreateTableWithIndex"></a>

Os índices secundários locais devem ser criados ao mesmo tempo que uma tabela é criada. Para fazer isso, use o parâmetro `create-table` e forneça as especificações para um ou mais índices secundários locais. O exemplo a seguir cria uma tabela (`Music`) para armazenar informações sobre músicas em uma coleção de músicas. A chave de partição é `Artist` e a chave de classificação é `SongTitle`. Um índice secundário, `AlbumTitleIndex`, no atributo `AlbumTitle` facilita consultas por título de álbum. 

```
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\"]}}]"
```

Você deve aguardar até que o DynamoDB crie a tabela e defina o status dessa tabela como `ACTIVE`. Depois disso, você poderá começar a inserir itens de dados na tabela. Você pode usar [describe-table](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/describe-table.html) para determinar o status da criação da tabela. 

## Descrever uma tabela com um índice secundário local
<a name="LCICli.DescribeTableWithIndex"></a>

Para obter mais informações sobre índices secundários locais em uma tabela, use o parâmetro `describe-table`. Para cada índice, você pode acessar seu nome, esquema de chaves e atributos projetados.

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

## Consultar um índice secundário local
<a name="LCICli.QueryAnIndex"></a>

Você pode usar a operação `query` em um índice secundário local de modo semelhante a como você `query` em uma tabela. Você deve especificar o nome do índice, os critérios de consulta da chave de classificação do índice e os atributos que deseja retornar. Neste exemplo, o índice é `AlbumTitleIndex` e a chave de classificação do índice é `AlbumTitle`. 

Os únicos atributos retornados são aqueles que foram projetados no índice. É possível modificar essa consulta para selecionar atributos não chave também, mas isso exigiria atividades de busca de tabela que são relativamente caras. Para obter mais informações sobre buscas de tabela, consulte [Projeções de atributo](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"} }'
```

# Gerenciar fluxos de trabalho complexos com transações do DynamoDB
<a name="transactions"></a>

As Amazon DynamoDB Transactions simplificam a experiência do desenvolvedor ao fazer alterações de tudo ou nada em vários itens dentro e entre tabelas. As transações fornecem atomicidade, consistência, isolamento e durabilidade (ACID) no DynamoDB, ajudando você a manter a correção dos dados em suas aplicações.

Você pode usar as APIs de leitura e gravação transacionais do DynamoDB para gerenciar fluxos de trabalho empresariais complexos que precisão de adição, atualização ou exclusão de vários itens como uma única operação tudo ou nada. Por exemplo, um desenvolvedor de videogames pode garantir que os perfis dos jogadores sejam atualizados corretamente quando eles trocam itens em um jogo ou fazem compras dentro do jogo.

Com a API de gravação de transações, você pode agrupar várias ações `Put`, `Update`, `Delete` e `ConditionCheck`. Você pode enviar as ações como uma única operação `TransactWriteItems` que é bem-sucedida ou falha como uma unidade. O mesmo é verdade para várias ações `Get`, que você pode agrupar e enviar como uma única operação `TransactGetItems`.

Não há custo adicional para habilitar transações para suas tabelas do DynamoDB. Você paga apenas pelas leituras ou gravações que fazem parte de sua transação. O DynamoDB realiza duas leituras subjacentes ou gravações de cada item na transação: uma para preparar a transação e outra para enviar a transação. Essas duas operações de leitura/gravação subjacentes são visíveis nas métricas do Amazon CloudWatch.

Para começar a usar as transações do DynamoDB, baixe o AWS SDK mais recente ou da AWS Command Line Interface (AWS CLI). Em seguida, siga o [Exemplo de transações do DynamoDB](transaction-example.md).

As seções a seguir fornecem uma visão geral detalhada das APIs de transação e como você pode usá-las no DynamoDB.

**Topics**
+ [Como funciona](transaction-apis.md)
+ [Usar o IAM com transações](transaction-apis-iam.md)
+ [Código de exemplo](transaction-example.md)

# Amazon DynamoDB Transactions: como funciona
<a name="transaction-apis"></a>

Com as Amazon DynamoDB Transactions, você pode agrupar várias ações juntas e enviá-las como uma única operação tudo ou nada `TransactWriteItems` ou `TransactGetItems`. As seções a seguir descrevem operações de API, gerenciamento de capacidade, práticas recomendadas e outros detalhes sobre o uso de operações transacionais no DynamoDB.

**Topics**
+ [API TransactWriteItems](#transaction-apis-txwriteitems)
+ [API TransactGetItems](#transaction-apis-txgetitems)
+ [Níveis de isolamento para transações do DynamoDB](#transaction-isolation)
+ [Tratamento de conflitos em transações com o DynamoDB](#transaction-conflict-handling)
+ [Usar APIs transacionais no DynamoDB Accelerator (DAX)](#transaction-apis-dax)
+ [Gerenciar capacidade para transações](#transaction-capacity-handling)
+ [Práticas recomendadas para transações](#transaction-best-practices)
+ [Usar APIs Transacionais com tabelas globais](#transaction-integration)
+ [Transações do DynamoDB comparadas com biblioteca de clientes de transações do AWSLabs](#transaction-vs-library)

## API TransactWriteItems
<a name="transaction-apis-txwriteitems"></a>

`TransactWriteItems` é uma operação de gravação síncrona e idempotente que agrupa até 100 ações de gravação em uma única operação tudo ou nada. Essas ações podem ter como destino até 100 itens distintos em uma ou mais tabelas do DynamoDB na mesma conta e região da AWS. O tamanho agregado dos itens na transação não podem exceder 4 MB. As ações são concluídas de forma atômica para que todas sejam bem-sucedidas ou nenhuma tenha êxito.

**nota**  
 Uma operação `TransactWriteItems` difere de uma operação `BatchWriteItem` em que todas as ações contidas devem ser concluídas com êxito, ou nenhuma alteração foi feita. Com uma operação `BatchWriteItem`, é possível que apenas as ações no lote sejam bem-sucedidas enquanto as outras não. 
 As transações não podem ser realizadas usando índices. 

Você não pode visar o mesmo item com várias operações dentro da mesma transação. Por exemplo, você não pode executar uma ação `ConditionCheck` e também uma `Update` no mesmo item na mesma transação.

Você pode adicionar os tipos a seguir de ações a uma transação:
+ `Put`: inicia uma operação `PutItem` para criar um novo item ou substituir um item antigo com um item novo, de forma condicional ou sem especificar qualquer condição.
+ `Update`: inicia uma operação `UpdateItem` para editar um atributo de item existente ou adicionar um novo item à tabela se ele já não existir. Use essa ação para adicionar, excluir ou atualizar atributos ou um item existente de forma condicional ou sem uma condição.
+ `Delete`: inicia uma operação `DeleteItem` para excluir um único item em uma tabela identificada por essa chave principal.
+ `ConditionCheck`: verifica se um item existe ou verifica a condição de atributos específicos do item.

Quando uma transação é concluída no DynamoDB, suas alterações começam a se propagar para índices secundários globais (GSIs), fluxos e backups. Essa propagação ocorre gradualmente: registros de fluxo da mesma transação podem aparecer em momentos diferentes e podem ser intercalados com registros de outras transações. Os consumidores do fluxo não devem presumir a atomicidade da transação ou as garantias de ordenação.

Para garantir um snapshot atômico dos itens modificados em uma transação, use a operação TransactGetItems para ler todos os itens relevantes juntos. Essa operação fornece uma visão consistente dos dados, garantindo que você veja todas as alterações de uma transação concluída ou nenhuma.

Como a propagação não é imediata, se uma tabela for restaurada do backup ([RestoreTableFromBackup](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_RestoreTableFromBackup.html)) ou exportada para um ponto anterior no tempo ([ExportTableToPointInTime](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ExportTableToPointInTime.html)) no meio da transação, ela poderá conter apenas algumas das alterações feitas durante uma transação recente.

### Potência igual
<a name="transaction-apis-txwriteitems-idempotency"></a>

Você pode, opcionalmente, incluir um token de cliente quando fizer uma chamada `TransactWriteItems` para garantir que a solicitação é *idempotente*. Realizar transações idempotentes ajuda a prevenir erros de aplicação se a mesma operação for enviada diversas vezes por conta de uma desconexão ou outro problema de conexão.

Se a chamada `TransactWriteItems` original for bem-sucedida, as chamadas `TransactWriteItems` subsequentes com o mesmo token de cliente retornarão com êxito sem nenhuma alteração. Se o parâmetro `ReturnConsumedCapacity` estiver definido, a chamada `TransactWriteItems` inicial retornará o número de unidades de capacidade de gravação consumidas para realizar as alterações. Chamadas `TransactWriteItems` subsequentes com o mesmo token de cliente devolvem o número de unidades de capacidade de leitura consumidas na leitura do item.

**Pontos importantes sobre idempotência**
+ Um token de cliente é válido por 10 minutos após a solicitação utilizada acabar. Depois de 10 minutos, quaisquer solicitações que usarem o mesmo token de cliente são tratadas como uma nova solicitação. Você não deve reutilizar o mesmo token de cliente para a mesma solicitação após 10 minutos.
+ Se você repetir uma solicitação com o mesmo token de cliente dentro de 10 minutos na janela de idempotência, mas alterar algum parâmetro de solicitação, o DynamoDB retornará uma exceção `IdempotentParameterMismatch`.

### Tratamento de erros para gravação
<a name="transaction-apis-txwriteitems-errors"></a>

Transações de gravação não são bem-sucedidas nas circunstâncias a seguir:
+ Quando uma condição em uma das expressões de condição não é alcançada.
+ Quando uma validação de transação ocorrer por conta de mais de uma ação na mesma operação `TransactWriteItems` ter como destino o mesmo item.
+ Quando uma solicitação `TransactWriteItems` entra em conflito com uma operação `TransactWriteItems` em andamento em um ou mais itens na operação `TransactWriteItems`. Nesse caso, a solicitação falha com um `TransactionCanceledException`.
+ Quando há capacidade provisionada insuficiente para a transação ser concluída.
+ Quando o tamanho de um item é muito maior (maior que 400 KB), ou um índice secundário local (LSI) se torna muito grande, ou um erro de validação semelhante ocorre por conta das alterações feitas pela transação.
+ Quando houver um erro de usuário, como formato de dados inválidos.

 Para obter mais informações sobre como os conflitos com operações `TransactWriteItems` são gerenciados, consulte [Tratamento de conflitos em transações com o DynamoDB](#transaction-conflict-handling).

## API TransactGetItems
<a name="transaction-apis-txgetitems"></a>

`TransactGetItems` é uma operação de leitura síncrona que agrupa até 100 ações `Get`. Essas ações podem ter como destino até 100 itens distintos em uma ou mais tabelas do DynamoDB na mesma conta e região da AWS. O tamanho agregado dos itens na transação não pode exceder 4 MB. 

As ações `Get` são realizadas de forma atômica para que todas sejam bem-sucedidas ou nenhuma tenha êxito:
+ `Get`: inicia uma operação `GetItem` para recuperar um conjunto de atributos do item com a chave primária fornecida. Se não houver item correspondente, `Get` não retornará quaisquer dados.

### Tratamento de erros para leitura
<a name="transaction-apis-txgetitems-errors"></a>

Transações de leitura não são bem-sucedidas nas circunstâncias a seguir:
+ Quando uma solicitação `TransactGetItems` entra em conflito com uma operação `TransactWriteItems` em andamento em um ou mais itens na operação `TransactGetItems`. Nesse caso, a solicitação falha com um `TransactionCanceledException`.
+ Quando há capacidade provisionada insuficiente para a transação ser concluída.
+ Quando houver um erro de usuário, como formato de dados inválidos.

 Para obter mais informações sobre como os conflitos com operações `TransactGetItems` são gerenciados, consulte [Tratamento de conflitos em transações com o DynamoDB](#transaction-conflict-handling).

## Níveis de isolamento para transações do DynamoDB
<a name="transaction-isolation"></a>

Os níveis de isolamento de operações transacionais (`TransactWriteItems` ou `TransactGetItems`) e outras operações são os seguintes.

### SERIALIZÁVEL
<a name="transaction-isolation-serializable"></a>

Isolamento *Serializável* garante que os resultados de várias operações concomitantes sejam os mesmos como se nenhuma operação começar com o anterior finalizado.

Há um isolamento serializável entre os tipos a seguir de operação:
+ Entre qualquer operação transacional e qualquer padrão de operação de gravação (`PutItem`, `UpdateItem` ou `DeleteItem`).
+ Entre qualquer operação transacional e qualquer padrão de operação de leitura (`GetItem`).
+ Entre uma operação `TransactWriteItems` e `TransactGetItems`.

Apesar de haver isolamento serializável entre operações transacionais, e cada padrão individual de gravação em uma operação `BatchWriteItem`, não há isolamento serializável entre a transação e a operação `BatchWriteItem` como uma unidade.

De modo semelhante, o nível de isolamento entre uma operação transacional e `GetItems` individual em uma operação `BatchGetItem` é serializável. Porém, o nível de isolamento entre a transação e a operação `BatchGetItem` como uma unidade é *confirmado para leitura*.

Uma única solicitação `GetItem` é serializável em relação a uma solicitação `TransactWriteItems` de duas formas, antes ou depois da solicitação `TransactWriteItems`. Várias solicitações `GetItem`, contra chaves em solicitações `TransactWriteItems`, podem ser executadas em qualquer ordem e, portanto, os resultados são *confirmado para leitura*.

Por exemplo, se solicitações `GetItem` para o item A e o item B forem executadas simultaneamente com uma solicitação `TransactWriteItems` que modifica o item A e o item B, existem quatro possibilidades:
+ Ambas as solicitações `GetItem` são executadas antes da solicitação `TransactWriteItems`.
+ Ambas as solicitações `GetItem` são executadas após a solicitação `TransactWriteItems`.
+ A solicitação `GetItem` para o item A é executada antes da solicitação `TransactWriteItems`. Para o item B, `GetItem` é executada após `TransactWriteItems`.
+ A solicitação `GetItem` para o item B é executada antes da solicitação `TransactWriteItems`. Para o item A, `GetItem` é executada após `TransactWriteItems`.

Você deverá usar `TransactGetItems` se preferir o nível de isolamento serializável para várias solicitações `GetItem`.

Se uma leitura não transacional for feita em vários itens que faziam parte da mesma solicitação de gravação de transação em andamento, é possível que você consiga ler o novo estado de alguns dos itens e o estado antigo dos outros itens. Você poderá ler o novo estado de todos os itens que faziam parte da solicitação de gravação da transação somente quando uma resposta bem-sucedida for recebida para a gravação transacional, indicando que a transação foi concluída.

Depois que a transação for concluída com êxito e uma resposta for recebida, as operações de leitura *finalmente consistente* subsequentes ainda poderão exibir o estado antigo por um curto período devido ao modelo de consistência final do DynamoDB. Para garantir a leitura dos dados mais atualizados imediatamente após uma transação, você deve usar leituras [*altamente consistentes*](HowItWorks.ReadConsistency.md#HowItWorks.ReadConsistency.Strongly) definindo `ConsistentRead` como verdadeiro.

### CONFIRMADO PARA LEITURA
<a name="transaction-isolation-read-committed"></a>

O isolamento *confirmado para leitura* garante que as operações de leitura sempre retornem valores confirmados para um item; a leitura nunca apresentará uma visualização do item representando um estado de uma gravação transacional que não teve êxito final. Isolamento confirmado para leitura não previne modificações do item imediatamente após operação de leitura.

O nível de isolamento é confirmado para leitura entre qualquer operação transacional e qualquer operação de leitura que envolva vários padrões de leitura (`BatchGetItem`, `Query` ou `Scan`). Se uma gravação transacional atualizar um item no meio de uma operação de `BatchGetItem`, `Query` ou `Scan`, a parte subsequente da operação de leitura retornará o novo valor confirmado [com `ConsistentRead)` ou possivelmente um valor confirmado anteriormente (leitura final consistente)].

### Resumo da operação
<a name="transaction-isolation-table"></a>

Para resumir, a tabela a seguir mostra os níveis de isolamento entre uma operação transacional (`TransactWriteItems` ou `TransactGetItems`) e outras operações.


| Operation | Nível de isolamento | 
| --- | --- | 
| `DeleteItem` | *Serializável* | 
| `PutItem` | *Serializável* | 
| `UpdateItem` | *Serializável* | 
| `GetItem` | *Serializável* | 
| `BatchGetItem` | *Confirmado para leitura*\$1 | 
| `BatchWriteItem` | *NÃO serializável*\$1 | 
| `Query` | *Confirmado para leitura* | 
| `Scan` | *Confirmado para leitura* | 
| Outra operação transacional | *Serializável* | 

Níveis marcados com asterisco (\$1) aplicam-se à operação como uma unidade. No entanto, ações individuais dentro dessas operações tem um nível de isolamento *serializável*.

## Tratamento de conflitos em transações com o DynamoDB
<a name="transaction-conflict-handling"></a>

Um conflito de transação pode correr em solicitações simultâneas no nível do item, em um item dentro de uma transação. Os conflitos de transação podem ocorrer nos seguintes casos: 
+ Uma solicitação `PutItem`, `UpdateItem` ou `DeleteItem` de um item conflita com uma solicitação `TransactWriteItems` em andamento que inclui o mesmo item.
+ Um item dentro de uma solicitação `TransactWriteItems` é parte de outra solicitação `TransactWriteItems` em andamento.
+ Um item dentro de uma solicitação `TransactGetItems` é parte de outra solicitação `TransactWriteItems`, `BatchWriteItem`, `PutItem`, `UpdateItem` ou `DeleteItem` em andamento.

**nota**  
Quando uma solicitação `PutItem`, `UpdateItem` ou `DeleteItem` é rejeitada, a solicitação falha com um `TransactionConflictException`, 
Se qualquer solicitação no nível do item dentro de `TransactWriteItems` ou `TransactGetItems` é rejeitada, a solicitação falha com um `TransactionCanceledException`. Se essa solicitação falhar, os AWS SDKs não tentarão repetir a solicitação.  
Se você estiver usando AWS SDK para Java, a exceção conterá a lista de [CancellationReasons](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_CancellationReason.html), em ordem de acordo com a lista de itens no parâmetro de solicitação `TransactItems`. Para outros idiomas, uma representação em string da lista é incluída na mensagem de erro de exceção. 
Se uma operação `TransactWriteItems` ou `TransactGetItems` em andamento entrar em conflito com uma solicitação `GetItem` simultânea, as duas podem ter êxito.

A métrica [TransactionConflict do CloudWatch](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/metrics-dimensions.html) é incrementada em cada solicitação que falhou no nível do item

## Usar APIs transacionais no DynamoDB Accelerator (DAX)
<a name="transaction-apis-dax"></a>

O DynamoDB Accelerator (DAX) oferece suporte a `TransactWriteItems` e `TransactGetItems` com os mesmos níveis de isolamento que no DynamoDB.

`TransactWriteItems` grava via DAX. O DAX passa uma chamada `TransactWriteItems` para o DynamoDB e retorna a resposta. Para preencher o cache após a gravação, o DAX chama `TransactGetItems` em segundo plano para cada item na operação `TransactWriteItems`, o que consome unidades de capacidade de leitura adicionais. (Para ter mais informações, consulte [Gerenciar capacidade para transações](#transaction-capacity-handling).) Essa funcionalidade permite manter simples a lógica da aplicação e usar o DAX para operações transacionais e não transacionais.

`TransactGetItems`Chamadas de são transmitidas pelo DAX sem que os itens sejam armazenados em cache localmente. É o mesmo comportamento para APIs de leitura fortemente consistente no DAX.

## Gerenciar capacidade para transações
<a name="transaction-capacity-handling"></a>

Não há custo adicional para habilitar transações para suas tabelas do DynamoDB. Você paga apenas pelas leituras ou gravações que fazem parte de sua transação. O DynamoDB realiza duas leituras subjacentes ou gravações de cada item na transação: uma para preparar a transação e outra para enviar a transação. Essas duas operações de leitura/gravação subjacente são visíveis nas métricas do Amazon CloudWatch.

Planeje para leituras e gravações adicionais que são necessárias por APIs transacionais ao provisionar a capacidade de suas tabelas. Por exemplo, suponha que sua aplicação execute uma transação por segundo e cada transação grave itens de 500 bytes em sua tabela. Cada item requer duas capacidades de gravação (WCUs): uma para preparar a transação e uma para enviar a transação. Portanto, você precisa provisionar seis WCUs na tabela. 

Se você usar o DynamoDB Accelerator (DAX) no exemplo anterior, use também as unidades de capacidade de leitura (RCUs) em cada item na chamada `TransactWriteItems`. Então, você precisa provisionar seis RCUs adicionais na tabela.

De forma semelhante, se sua aplicação executa uma transação de leitura por segundo, e cada transação lê itens de 500 bytes na sua tabela, é preciso prover seis unidades de capacidade de leitura (RCUs) na tabela. A leitura de cada item requer duas RCUs: uma para preparar a transação e uma para enviar a transação.

Além disso, comportamento de SDK padrão é tentar transações novamente em caso de uma exceção `TransactionInProgressException`. Planeje para as unidades de capacidade de leitura adicional (RCUs) que essas tentativas repetitivas consumem. O mesmo é verdade se você estiver tentando novamente transações em seu código usando um `ClientRequestToken`.

## Práticas recomendadas para transações
<a name="transaction-best-practices"></a>

Considere as seguintes práticas recomendadas ao usar transações do DynamoDB.
+ Habilitar Auto Scaling nas suas tabelas, ou garantir que você tem capacidade de throughput suficiente para realizar as duas operações de leitura ou gravação em cada item na transação.
+ Se não estiver usando um SDK fornecido pela AWS, inclua um atributo `ClientRequestToken` quando realizar uma chamada `TransactWriteItems` para garantir que a solicitação é idempotente.
+ Não agrupe operações em uma transação se não for necessário. Por exemplo, se uma transação única com 10 operações puder ser separada em várias transações sem comprometimento da exatidão do aplicativo, recomendamos separar a transação. Transações mais simples melhorar a taxa de transferência e têm maior chance de êxito. 
+ Transações múltiplas atualizando os mesmos itens simultaneamente podem causar conflitos que cancelam as transações. Recomendamos as práticas recomendadas do DynamoDB a seguir para modelagem de dados a fim de minimizar esses conflitos.
+ Se um conjunto de atributos for frequentemente atualizado entre vários itens como parte de uma única transação, considere agrupar os atributos em um único item para reduzir o escopo da transação.
+ Evite usar transações para adicionar dados no grupo. Para gravações em grupo, é melhor usar `BatchWriteItem`.

## Usar APIs Transacionais com tabelas globais
<a name="transaction-integration"></a>

As operações transacionais oferecem garantia de atomicidade, consistência, isolamento e durabilidade (ACID) somente na região da AWS em que a API de gravação foi invocada. As transações não são compatíveis entre regiões em tabelas globais. Por exemplo, suponha que você tenha uma tabela global com réplicas nas regiões Leste dos EUA (Ohio) e Oeste dos EUA (Oregon) e execute uma operação `TransactWriteItems` na região Leste dos EUA (Norte da Virgínia). Você pode observar transações parcialmente concluídas na região Oeste dos EUA (Oregon) conforme as alterações são replicadas. As alterações só serão replicadas para outras regiões quando forem confirmadas na região de origem.

## Transações do DynamoDB comparadas com biblioteca de clientes de transações do AWSLabs
<a name="transaction-vs-library"></a>

As transações do DynamoDB fornecem uma substituição mais eficiente em termos de custos, efetiva e com maior performance para as transações da biblioteca de clientes do [AWSLabs](https://github.com/awslabs). Sugerimos atualizar os aplicativos para usar com as APIs de transação do lado do servidor nativas.

# Usar o IAM com transações do DynamoDB
<a name="transaction-apis-iam"></a>

Você pode usar o AWS Identity and Access Management (IAM) para restringir as ações que as operações transacionais podem executar no Amazon DynamoDB. Para obter mais informações sobre como usar as políticas do IAM no DynamoDB, consulte [Políticas baseadas em identidade para o DynamoDB](security_iam_service-with-iam.md#security_iam_service-with-iam-id-based-policies).

Permissões para `Put`, `Update`, `Delete`, e ações `Get` são governadas pelas permissões usadas para operações `PutItem`, `UpdateItem`, `DeleteItem` e `GetItem` subjacentes. Para a ação `ConditionCheck`, é possível usar a permissão `dynamodb:ConditionCheckItem` nas políticas do IAM.

Veja a seguir exemplos de políticas do IAM que você pode usar para configurar transações do DynamoDB.

## Exemplo 1: permitir operações transacionais
<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"
            ]
        }
    ]
}
```

------

## Exemplo 2: permitir apenas operações transacionais
<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"
                    ]
                }
            }
        }
    ]
}
```

------

## Exemplo 3: permitir leituras e gravações não transacionais e bloquear leituras e gravações transacionais
<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"
             ]
         }
    ]
}
```

------

## Exemplo 4: evitar que informações sejam devolvidas com a falha ConditionCheck
<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"
                }
            }
        }
    ]
}
```

------

# Exemplo de transações do DynamoDB
<a name="transaction-example"></a>

Como exemplo de uma situação em que as Amazon DynamoDB Transactions podem ser úteis, considere este exemplo de aplicação Java para um marketplace online.

A aplicação tem três tabelas do DynamoDB no backend:
+ `Customers`: esta tabela armazena detalhes sobre os clientes do marketplace. Sua chave primária é um identificador exclusivo `CustomerId`.
+ `ProductCatalog`: esta tabela armazena detalhes como preço e disponibilidade sobre os produtos para venda no mercado. Sua chave primária é um identificador exclusivo `ProductId`.
+ `Orders`: esta tabela armazena detalhes sobre os pedidos do marketplace. Sua chave primária é um identificador exclusivo `OrderId`.

## Fazer um pedido
<a name="transaction-example-write-order"></a>

Os trechos de código a seguir ilustram como usar transações do DynamoDB para coordenar as várias etapas necessárias para criar e processar um pedido. O uso de uma única operação de tudo ou nada garante que, se qualquer parte da transação falhar, nenhuma ação na transação será executada e nenhuma alteração será feita.

Neste exemplo, você configura um pedido de um cliente cujo `customerId` é `09e8e9c8-ec48`. Em seguida, execute-o como uma única transação usando o seguinte fluxo de trabalho simples de processamento de pedidos:

1. Determine se o ID do cliente é válido.

1. Verifique se o produto é `IN_STOCK` e atualize o status do produto para `SOLD`.

1. Certifique-se de que o pedido ainda não exista e crie-o.

### Validar o cliente
<a name="transaction-example-order-part-a"></a>

Primeiro, defina uma ação para verificar se um cliente com `customerId` igual a `09e8e9c8-ec48` existe na tabela de clientes.

```
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 + ")");
```

### Atualizar o status do produto
<a name="transaction-example-order-part-b"></a>

Em seguida, defina uma ação para atualizar o status do produto para `SOLD` se a condição do status atual do produto `IN_STOCK` for `true`. Configurar a opção `ReturnValuesOnConditionCheckFailure` retornará o item se o atributo de status do produto do item não for igual a `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);
```

### Criar o pedido
<a name="transaction-example-order-part-c"></a>

Por último, crie o pedido, desde que um pedido com esse `OrderId` ainda não exista.

```
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 + ")");
```

### Executar a transação
<a name="transaction-example-order-part-d"></a>

O exemplo a seguir ilustra como executar as ações definidas anteriormente como uma única operação tudo ou nada.

```
    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());
    }
```

## Ler os detalhes do pedido
<a name="transaction-example-read-order"></a>

O exemplo a seguir mostra como ler a ordem concluída transacionalmente entre as tabelas `Orders` e `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());
}
```

# Captura de dados de alterações com o Amazon DynamoDB
<a name="streamsmain"></a>

Muitas aplicações podem se beneficiar da capacidade de capturar alterações nos itens armazenados em uma tabela do DynamoDB no momento em que elas ocorrem. Veja a seguir alguns exemplos de casos de uso:
+ Uma aplicação móvel popular modifica os dados em uma tabela do DynamoDB a uma taxa de milhares de atualizações por segundo. Outra aplicação captura e armazena dados sobre essas atualizações, fornecendo métricas de uso quase em tempo real para a aplicação móvel.
+ Uma aplicação financeira modifica os dados do mercado de ações em uma tabela do DynamoDB. Diferentes aplicações executadas em paralelo acompanham essas mudanças em tempo real, calculam o valor em risco e reequilibram automaticamente as carteiras com base nos movimentos dos preços das ações.
+ Sensores em veículos de transporte e equipamentos industriais enviam dados para uma tabela do DynamoDB. Diferentes aplicações monitoram a performance e enviam alertas de mensagens quando um problema é detectado, preveem possíveis defeitos aplicando algoritmos de machine learning e compactam e arquivam dados no Amazon Simple Storage Service (Amazon S3).
+ Uma aplicação envia notificações automaticamente aos dispositivos móveis de todos os jogadores de um grupo assim que um deles carrega uma nova imagem.
+ Um novo cliente adiciona dados a uma tabela do DynamoDB. Esse evento invoca outra aplicação que envia um e-mail de boas-vindas ao novo cliente.

O DynamoDB oferece suporte a streaming de registros de captura de dados de alteração em nível de item em tempo quase real. Você pode criar aplicações que consomem esses fluxos e executam ações com base no conteúdo.

**nota**  
Não há suporte para a adição de tags ao DynamoDB Streams e o uso de [controle de acesso por atributo (ABAC)](access-control-resource-based.md) com o DynamoDB Streams.

O vídeo a seguir apresenta uma introdução sobre o conceito de captura de dados de alteração.

[![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**
+ [Opções de streaming para captura de dados de alteração](#streamsmain.choose)
+ [Use o Kinesis Data Streams para capturar alterações do DynamoDB](kds.md)
+ [Capturar dados de alterações para o DynamoDB Streams](Streams.md)

## Opções de streaming para captura de dados de alteração
<a name="streamsmain.choose"></a>

O DynamoDB oferece dois modelos de streaming para captura de dados de alteração: Kinesis Data Streams para DynamoDB e DynamoDB Streams.

Para ajudar você a escolher a solução certa para sua aplicação, a tabela a seguir resume os recursos de cada modelo de streaming. 

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

É possível habilitar ambos os modelos de streaming na mesma tabela do DynamoDB.

O vídeo a seguir aprofunda-se nas diferenças entre as duas opções.

[![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)


# Use o Kinesis Data Streams para capturar alterações do DynamoDB
<a name="kds"></a>

É possível usar o Amazon Kinesis Data Streams para capturar alterações no Amazon DynamoDB.

O Kinesis Data Streams capta alterações no nível de item em qualquer DynamoDB e as replica em um [fluxo de dados do Kinesis](https://docs.aws.amazon.com/streams/latest/dev/introduction.html). Suas aplicações podem acessar esse fluxo e visualizar as alterações em nível de item praticamente em tempo real. Você pode capturar e armazenar continuamente terabytes de dados por hora. Aproveite o tempo de retenção de dados mais longo e com o recurso de distribuição avançada para atingir simultaneamente duas ou mais aplicações downstream. Outros benefícios incluem auditoria adicional e transparência de segurança.

O Kinesis Data Streams também oferece acesso ao [Amazon Kinesis Data Firehose](https://docs.aws.amazon.com/firehose/latest/dev/what-is-this-service.html) e ao [Amazon Managed Service for Apache Flink](https://docs.aws.amazon.com/kinesisanalytics/latest/dev/what-is.html). Isso permite construir aplicações para alimentar painéis em tempo real, gerar alertas, implementar definições de preço e de publicidade dinâmicas e implementar análises de dados e algoritmos de machine learning sofisticados.

**nota**  
O uso de Kinesis Data Streams para DynamoDB está sujeito aos [preços do Kinesis Data Streams](https://aws.amazon.com/kinesis/data-streams/pricing/) para o fluxo de dados e aos [preços do DynamoDB](https://aws.amazon.com/dynamodb/pricing/) para a tabela de origem.

Para habilitar o streaming do Kinesis em uma tabela do DynamoDB usando o console ou o AWS CLI SDK para Java, consulte [Conceitos básicos do Kinesis Data Streams para o Amazon DynamoDB](kds_gettingstarted.md).

**Topics**
+ [Como o Kinesis Data Streams funciona com o DynamoDB](#kds_howitworks)
+ [Conceitos básicos do Kinesis Data Streams para o Amazon DynamoDB](kds_gettingstarted.md)
+ [Usar fragmentos e métricas com o DynamoDB Streams e o Kinesis Data Streams](kds_using-shards-and-metrics.md)
+ [Usar políticas do IAM para o Amazon Kinesis Data Streams e Amazon DynamoDB](kds_iam.md)

## Como o Kinesis Data Streams funciona com o DynamoDB
<a name="kds_howitworks"></a>

Quando um fluxo de dados do Kinesis é habilitado para uma tabela do DynamoDB, a tabela envia um registro de dados que captura alterações nos dados dessa tabela. Esse registro de dados inclui:
+ O horário específico em que um item foi criado, atualizado ou excluído recentemente
+ A chave primária desse item
+ Um snapshot do registro antes da modificação
+ Um snapshot do registro após a modificação 

Esses registros de dados são capturados e publicados praticamente em tempo real. Depois de gravados no fluxo de dados do Kinesis, poderão ser lidos como qualquer outro registro. É possível usar a Biblioteca de clientes Kinesis, usar o AWS Lambda, chamar a API do Kinesis Data Streams e usar outros serviços conectados. Para obter mais informações, consulte [Ler dados do Amazon Kinesis Data Streams](https://docs.aws.amazon.com/streams/latest/dev/building-consumers.html) no Guia do desenvolvedor do Amazon Kinesis Data Streams.

Essas alterações nos dados também são capturadas de forma assíncrona. O Kinesis não afetará a performance da tabela da qual estiver fazendo streaming. Os registros de fluxo armazenados no fluxo de dados do Kinesis também são criptografados em repouso. Para obter mais informações, consulte [Proteção de dados no Amazon Kinesis Data Streams](https://docs.aws.amazon.com/streams/latest/dev/server-side-encryption.html).

Os registros de fluxo de dados do Kinesis poderão aparecer em uma sequência diferente da sequência na qual ocorreram as modificações dos itens. As mesmas notificações de item também poderão aparecer mais de uma vez no fluxo. Confira o atributo `ApproximateCreationDateTime` para identificar a sequência em que as modificações dos itens ocorreram e para identificar registros duplicados. 

Ao habilitar um fluxo de dados do Kinesis como destino de streaming de uma tabela do DynamoDB, você pode configurar a precisão dos valores de `ApproximateCreationDateTime` em milissegundos ou microssegundos. Por padrão, `ApproximateCreationDateTime` indica a hora da alteração em milissegundos. Além disso, é possível alterar esse valor em um destino de streaming ativo. Depois dessa atualização, os registros de fluxo gravados no Kinesis terão valores de `ApproximateCreationDateTime` com a precisão desejada. 

Valores binários gravados no DynamoDB devem ser codificados em [formato codificado em base64](HowItWorks.NamingRulesDataTypes.md). No entanto, quando os registros de dados são gravados em um fluxo de dados do Kinesis, esses valores binários são codificados em base64 pela segunda vez. Ao ler esses registros de um fluxo de dados do Kinesis, para recuperar os valores binários brutos, as aplicações devem decodificar esses valores duas vezes.

O DynamoDB cobra pelo uso para Kinesis Data Streams em unidades de captura de dados de alterações. 1 KB de alteração por item único conta como uma unidade de captura de dados de alteração. Os KB de alteração em cada item são calculados pela maior das imagens de “antes” e “depois” do item gravado no fluxo, usando a mesma lógica que o [consumo de unidades de capacidade para operações de gravação](read-write-operations.md#write-operation-consumption). Não é necessário provisionar a capacidade de throughput para unidades de captura de dados de alteração, semelhante a como o modo [sob demanda](capacity-mode.md#capacity-mode-on-demand) do DynamoDB funciona.

### Ativar um fluxo de dados do Kinesis para a tabela do DynamoDB
<a name="kds_howitworks.enabling"></a>

Você pode habilitar ou desabilitar o streaming para o Kinesis em uma tabela existente do DynamoDB usando o Console de gerenciamento da AWS, o AWS SDK ou a AWS Command Line Interface (AWS CLI).
+ Só é possível fazer o streaming de dados do DynamoDB para o Kinesis Data Streams na mesma conta da AWS e região da AWS que sua tabela. 
+ Só é possível fazer o streaming de dados de uma tabela do DynamoDB para um fluxo de dados do Kinesis.

  

### Alterar um destino do Kinesis Data Streams em uma tabela do DynamoDB
<a name="kds_howitworks.makingchanges"></a>

Por padrão, todos os registros de fluxo de dados do Kinesis incluem um atributo `ApproximateCreationDateTime`. Esse atributo representa um carimbo de data e hora, em milissegundos, da hora aproximada em que cada registro foi criado. Você pode alterar a precisão desses valores usando o [https://console.aws.amazon.com/kinesis](https://console.aws.amazon.com/kinesis), o SDK ou a AWS CLI. 

# Conceitos básicos do Kinesis Data Streams para o Amazon DynamoDB
<a name="kds_gettingstarted"></a>

Esta seção descreve como usar o Kinesis Data Streams para tabelas do Amazon DynamoDB com o console do Amazon DynamoDB, a AWS Command Line Interface (AWS CLI) e a API.

## Criar um fluxo de dados ativo do Amazon Kinesis
<a name="kds_gettingstarted.making-changes"></a>

Todos esses exemplos usam a tabela `Music` do DynamoDB que foi criada como parte do tutorial [Conceitos básicos do DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStartedDynamoDB.html).

Para saber mais sobre como criar consumidores e conectar seu fluxo de dados do Kinesis a outros produtos da AWS, consulte [Ler dados do Amazon Kinesis Data Streams](https://docs.aws.amazon.com/streams/latest/dev/building-consumers.html) no *Guia do desenvolvedor do Amazon Kinesis Data Streams*.

**nota**  
 Quando você estiver usando fragmentos do KDS pela primeira vez, recomendamos configurá-los para que aumentem e reduzam a escala verticalmente de acordo com os padrões de uso. Depois de acumular mais dados sobre os padrões de uso, você poderá ajustar os fragmentos em seu fluxo para fazer a correspondência. 

------
#### [ Console ]

1. Faça login no Console de gerenciamento da AWS e abra o console do Kinesis em [ https://console.aws.amazon.com/kinesis/](https://console.aws.amazon.com/kinesis/).

1. Escolha **Create data stream** (Criar fluxo de dados) e siga as instruções para criar um fluxo chamado `samplestream`. 

1. Abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/).

1. No painel de navegação, no lado esquerdo do console, selecione **Tables** (Tabelas).

1. Escolha a tabela **Music**.

1. Escolha a guia **Exports and streams** (Exportações e fluxos).

1. (Opcional) Em **Detalhes do stream de dados do Amazon Kinesis**, você pode alterar a precisão do carimbo de data e hora do registro de microssegundos (padrão) para milissegundos. 

1. Escolha **samplestream** na lista suspensa.

1. Escolha o botão **Ativar**.

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

1. Criar um fluxo de dados do Kinesis denominado `samplestream` usando o [comando create-stream](https://docs.aws.amazon.com/cli/latest/reference/kinesis/create-stream.html).

   ```
   aws kinesis create-stream --stream-name samplestream --shard-count 3 
   ```

   Consulte [Considerações sobre gerenciamento de fragmentos para o Kinesis Data Streams](kds_using-shards-and-metrics.md#kds_using-shards-and-metrics.shardmanagment) antes de definir o número de fragmentos para o fluxo de dados do Kinesis.

1. Verifique se o stream do Kinesis está ativo e pronto para uso usando o [comando describe-stream](https://docs.aws.amazon.com/cli/latest/reference/kinesis/describe-stream.html).

   ```
   aws kinesis describe-stream --stream-name samplestream
   ```

1. Habilite o streaming do Kinesis na tabela do DynamoDB usando o comando `enable-kinesis-streaming-destination` do DynamoDB. Substitua o valor de `stream-arn` pelo que foi retornado por `describe-stream` na etapa anterior. Opcionalmente, habilite o streaming com uma precisão mais granular (microssegundos) dos valores de carimbo de data e hora retornados em cada registro.

   Habilite o streaming com precisão de carimbo de data e hora em microssegundos:

   ```
   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
   ```

   Ou habilite o streaming com a precisão padrão do carimbo de data e hora (milissegundos):

   ```
   aws dynamodb enable-kinesis-streaming-destination \
     --table-name Music \
     --stream-arn arn:aws:kinesis:us-west-2:12345678901:stream/samplestream
   ```

1. Verifique se o streaming do Kinesis está ativa na tabela usando o comando `describe-kinesis-streaming-destination` do DynamoDB.

   ```
   aws dynamodb describe-kinesis-streaming-destination --table-name Music
   ```

1. Grave os dados na tabela do DynamoDB usando o comando `put-item`, conforme descrito no [Guia do desenvolvedor do 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. Use o comando [get-records](https://docs.aws.amazon.com/cli/latest/reference/kinesis/get-records.html) da CLI do Kinesis para recuperar o conteúdo de fluxo do Kinesis. Em seguida, use o trecho de código a seguir para desserializar o conteúdo do fluxo.

   ```
   /**
    * 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. Siga as instruções no Guia do desenvolvedor do Kinesis Data Streams para [criar](https://docs.aws.amazon.com/streams/latest/dev/kinesis-using-sdk-java-create-stream.html) um fluxo de dados do Kinesis chamada `samplestream` usando Java.

   Consulte [Considerações sobre gerenciamento de fragmentos para o Kinesis Data Streams](kds_using-shards-and-metrics.md#kds_using-shards-and-metrics.shardmanagment) antes de definir o número de fragmentos para o fluxo de dados do Kinesis. 

1. Use o trecho de código a seguir para habilitar a transmissão do Kinesis na tabela do DynamoDB. Opcionalmente, habilite o streaming com uma precisão mais granular (microssegundos) dos valores de carimbo de data e hora retornados em cada registro. 

   Habilite o streaming com precisão de carimbo de data e hora em microssegundos:

   ```
   EnableKinesisStreamingConfiguration enableKdsConfig = EnableKinesisStreamingConfiguration.builder()
     .approximateCreationDateTimePrecision(ApproximateCreationDateTimePrecision.MICROSECOND)
     .build();
   
   EnableKinesisStreamingDestinationRequest enableKdsRequest = EnableKinesisStreamingDestinationRequest.builder()
     .tableName(tableName)
     .streamArn(kdsArn)
     .enableKinesisStreamingConfiguration(enableKdsConfig)
     .build();
   
   EnableKinesisStreamingDestinationResponse enableKdsResponse = ddbClient.enableKinesisStreamingDestination(enableKdsRequest);
   ```

   Ou habilite o streaming com a precisão padrão do carimbo de data e hora (milissegundos):

   ```
   EnableKinesisStreamingDestinationRequest enableKdsRequest = EnableKinesisStreamingDestinationRequest.builder()
     .tableName(tableName)
     .streamArn(kdsArn)
     .build();
   
   EnableKinesisStreamingDestinationResponse enableKdsResponse = ddbClient.enableKinesisStreamingDestination(enableKdsRequest);
   ```

1. Siga as instruções do [Kinesis Data Streams developer guide](https://docs.aws.amazon.com/streams/latest/dev/building-consumers.html) (Guia do desenvolvedor do Kinesis Data Streams) para *ler* o fluxo de dados criado.

1. Use o trecho de código a seguir para desserializar o conteúdo do fluxo

   ```
   /**
    * 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());
   }
   ```

------

## Alterar um fluxo de dados ativo do Amazon Kinesis
<a name="kds_gettingstarted.making-changes"></a>

Esta seção descreve como alterar uma configuração ativa do Kinesis Data Streams para o DynamoDB usando o console, a AWS CLI e a API.

**Console de gerenciamento da AWS**

1. Abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/).

1. Acesse a tabela.

1. Escolha **Exportações e streams**.

**AWS CLI**

1. Chame `describe-kinesis-streaming-destination` para confirmar se o fluxo está `ACTIVE`. 

1. Chame `UpdateKinesisStreamingDestination`, como neste exemplo:

   ```
   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. Chame `describe-kinesis-streaming-destination` para confirmar se o fluxo está `UPDATING`.

1. Chame `describe-kinesis-streaming-destination` periodicamente até que o status de streaming volte a ser `ACTIVE`. Normalmente, demora até 5 minutos para que as atualizações de precisão do carimbo de data e hora entrem em vigor. A atualização desse status indicará que a operação terá sido concluída e que o novo valor de precisão será aplicado em registros futuros.

1. Grave na tabela usando `putItem`.

1. Use o comando `get-records` do Kinesis para obter o conteúdo do fluxo.

1. Confirme se `ApproximateCreationDateTime` das gravações tem a precisão desejada.

**API Java**

1. Forneça um trecho de código que construa uma solicitação `UpdateKinesisStreamingDestination` e uma resposta `UpdateKinesisStreamingDestination`. 

1. Forneça um trecho de código que construa uma solicitação `DescribeKinesisStreamingDestination` e uma `DescribeKinesisStreamingDestination response`.

1. Chame `describe-kinesis-streaming-destination` periodicamente até que o status de streaming volte a ser `ACTIVE`, indicando que a atualização foi concluída e que o novo valor de precisão será aplicado em registros futuros.

1. Faça gravações na tabela.

1.  Faça uma leitura do fluxo e desserialize o conteúdo do fluxo.

1. Confirme se `ApproximateCreationDateTime` das gravações tem a precisão desejada.

# Usar fragmentos e métricas com o DynamoDB Streams e o Kinesis Data Streams
<a name="kds_using-shards-and-metrics"></a>

## Considerações sobre gerenciamento de fragmentos para o Kinesis Data Streams
<a name="kds_using-shards-and-metrics.shardmanagment"></a>

Um fluxo de dados do Kinesis contabiliza o throughput em [fragmentos](https://docs.aws.amazon.com/streams/latest/dev/key-concepts.html). No Amazon Kinesis Data Streams, você pode escolher entre os modos **sob demanda** e **provisionado** para os fluxos de dados. 

Recomendamos usar o modo sob demanda para seu fluxo de dados do Kinesis se sua workload de gravação do DynamoDB for altamente variável e imprevisível. No modo sob demanda, nenhum planejamento de capacidade é necessário, já que o Kinesis Data Streams gerencia automaticamente os fragmentos para fornecer o throughput necessário.

Para workloads previsíveis, você pode usar o modo provisionado para seu fluxo de dados do Kinesis. No modo provisionado, você precisa especificar o número de fragmentos para o fluxo de dados a fim de acomodar os registros de captura de dados de alterações do DynamoDB. Para determinar o número de fragmentos de que o fluxo de dados do Kinesis precisará para oferecer suporte à sua tabela do DynamoDB, são necessários os seguintes valores de entrada:
+ O tamanho médio do registro da tabela do DynamoDB em bytes (`average_record_size_in_bytes`).
+ O número máximo de operações de gravação que a tabela do DynamoDB executará por segundo. Isso inclui operações de criação, exclusão e atualização executadas pelas aplicações, bem como operações geradas automaticamente, como operações de exclusão geradas por vida útil (`write_throughput`).
+ O percentual de operações de atualização e substituição que você executou na tabela em comparação com operações de criação ou exclusão (`percentage_of_updates`). As operações de atualização e substituição replicam as imagens antigas e novas do item modificado para o fluxo. Isso gera o dobro do tamanho do item do DynamoDB.

Você pode calcular o número de fragmentos (`number_of_shards`) necessários para o fluxo de dados do Kinesis usando os valores de entrada na seguinte fórmula:

```
number_of_shards = ceiling( max( ((write_throughput * (4+percentage_of_updates) * average_record_size_in_bytes) / 1024 / 1024), (write_throughput/1000)), 1)
```

Por exemplo, você tem um throughput máximo de 1.040 operações de gravação por segundo (`write_throughput`) com um tamanho médio de registro de 800 bytes (`average_record_size_in_bytes)`. Se 25% dessas operações de gravação forem operações de atualização (`percentage_of_updates`), serão necessários dois fragmentos (`number_of_shards`) para acomodar o throughput de streaming do DynamoDB:

```
ceiling( max( ((1040 * (4+25/100) * 800)/ 1024 / 1024), (1040/1000)), 1).
```

Considere o seguinte antes de usar a fórmula para calcular o número de fragmentos necessários com o modo provisionado para fluxos de dados do Kinesis:
+ Essa fórmula ajuda a estimar o número de fragmentos que serão necessários para acomodar seus registros de dados de alterações do DynamoDB. Ela não representa o número total de fragmentos necessários no fluxo de dados do Kinesis, como o número de fragmentos necessários para oferecer suporte aos consumidores adicionais de fluxos de dados do Kinesis.
+ Ainda será possível ocorrer exceções de throughput de leitura e gravação no modo provisionado se o fluxo de dados não for configurado para lidar com o throughput máximo. Nesse caso, será preciso escalar manualmente o fluxo para acomodar o tráfego de dados. 
+ Essa fórmula leva em consideração o inchaço adicional gerado pelo DynamoDB antes de fazer streaming dos registros de dados dos logs de alterações para o fluxo de dados do Kinesis.

Para saber mais sobre os modos de capacidade no Kinesis Data Streams, consulte [Choosing the Data Stream Capacity Mode](https://docs.aws.amazon.com/streams/latest/dev/how-do-i-size-a-stream.html). Para saber mais sobre a diferença de preços entre os diferentes modos de capacidade, consulte [Preços do Amazon Kinesis Data Streams](https://aws.amazon.com/kinesis/data-streams/pricing/).

## Monitorar a captura de dados de alterações com o Kinesis Data Streams
<a name="kds_using-shards-and-metrics.monitoring"></a>

O DynamoDB fornece várias métricas do Amazon CloudWatch que ajudam a monitorar a replicação da captura de dados de alterações para o Kinesis. Para obter uma lista completa de métricas do CloudWatch, consulte [Métricas e dimensões do DynamoDB](metrics-dimensions.md).

Para determinar se o fluxo tem capacidade suficiente, recomendamos monitorar os seguintes itens durante a ativação do fluxo e na produção:
+ `ThrottledPutRecordCount`: o número de registros aos quais o fluxo de dados do Kinesis aplicou controle de utilização devido à capacidade insuficiente do fluxo de dados do Kinesis. O `ThrottledPutRecordCount` deve permanecer o mais baixo possível, embora você possa sentir algum controle de utilização durante picos excepcionais de uso. O DynamoDB tenta novamente enviar os registros limitados ao fluxo de dados do Kinesis, mas isso pode resultar em maior latência de replicação. 

  Se você perceber controle de utilização excessivo e regular, talvez seja necessário aumentar o número de fragmentos de fluxos do Kinesis proporcionalmente ao throughput de gravação observada da tabela. Para saber mais sobre a determinação do tamanho de um fluxo de dados do Kinesis, consulte [Como determinar o tamanho inicial de um fluxo de dados do Kinesis](https://docs.aws.amazon.com/streams/latest/dev/amazon-kinesis-streams.html#how-do-i-size-a-stream).
+ `AgeOfOldestUnreplicatedRecord`: o tempo decorrido desde a que alteração de nível de item mais antiga ainda a ser replicada para o fluxo de dados do Kinesis surgiu na tabela do DynamoDB. Em condições normais de operação, `AgeOfOldestUnreplicatedRecord` deve estar na ordem dos milissegundos. Esse número aumenta de acordo com as tentativas de replicação malsucedidas quando elas são causadas por opções de configuração controladas pelo cliente.

   Se a métrica `AgeOfOldestUnreplicatedRecord` exceder 168 horas, a replicação das alterações no nível do item da tabela do DynamoDB para o fluxo de dados do Kinesis será automaticamente desabilitada.

  São exemplos de configurações controladas pelo cliente que levam a tentativas de replicação malsucedidas: uma capacidade de fluxo de dados do Kinesis com provisionamento insuficiente, o que leva a controle de utilização excessivo, ou uma atualização manual das políticas de acesso do fluxo de dados do Kinesis que impede que o DynamoDB adicione dados ao fluxo de dados. Para manter essa métrica no mínimo possível, talvez seja necessário garantir o provisionamento correto da capacidade do fluxo de dados do Kinesis e que as permissões do DynamoDB permaneçam inalteradas. 
+ `FailedToReplicateRecordCount`: número de registros que o DynamoDB não conseguiu replicar para o fluxo de dados do Kinesis. Determinados itens com mais de 34 KB podem se expandir em tamanho para alterar registros de dados maiores que o limite de 1 MB para itens do Kinesis Data Streams. Essa expansão de tamanho ocorre quando os itens com mais de 34 KB contêm um grande número de valores de atributos booleanos ou vazios. Valores de atributos booleanos e vazios são armazenados como 1 byte no DynamoDB, mas expandem até 5 bytes quando são serializados usando JSON padrão para replicação do Kinesis Data Streams. O DynamoDB não consegue replicar esses registros de alteração para o fluxo de dados do Kinesis. O DynamoDB ignora esses registros de dados de alteração e continua automaticamente a replicar registros subsequentes. 

   

Você pode criar alarmes do Amazon CloudWatch que enviam uma mensagem do Amazon Simple Notification Service (Amazon SNS) para notificação quando qualquer uma das métricas anteriores exceder um limite específico. 

# Usar políticas do IAM para o Amazon Kinesis Data Streams e Amazon DynamoDB
<a name="kds_iam"></a>

Na primeira vez que você habilitar o Amazon Kinesis Data Streams para Amazon DynamoDB, o DynamoDB criará automaticamente uma função vinculada ao serviço do AWS Identity and Access Management (IAM) para você. Esta função, `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication`, permite que o DynamoDB gerencie a replicação de alterações em nível de item no Kinesis Data Streams em seu nome. Não exclua essa função vinculada ao serviço.

Para ter mais informações sobre perfis vinculados ao serviço, consulte [Criar um perfil vinculado ao serviço](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html) no *Guia do usuário do IAM*.

**nota**  
O DynamoDB não oferece suporte a condições baseadas em etiqueta para políticas do IAM.

Para habilitar o Amazon Kinesis Data Streams para o Amazon DynamoDB, é necessário ter as seguintes permissões na tabela:
+ `dynamodb:EnableKinesisStreamingDestination`
+ `kinesis:ListStreams`
+ `kinesis:PutRecords`
+ `kinesis:DescribeStream`

A fim de descrever o Amazon Kinesis Data Streams para Amazon DynamoDB para determinada tabela do DynamoDB, é necessário ter as permissões a seguir na tabela.
+ `dynamodb:DescribeKinesisStreamingDestination`
+ `kinesis:DescribeStreamSummary`
+ `kinesis:DescribeStream`

A fim de desabilitar o Amazon Kinesis Data Streams para o Amazon DynamoDB, é necessário ter permissões a seguir na tabela.
+ `dynamodb:DisableKinesisStreamingDestination`

Para atualizar o Amazon Kinesis Data Streams para o Amazon DynamoDB, é necessário ter as permissões a seguir na tabela.
+ `dynamodb:UpdateKinesisStreamingDestination`

Os exemplos a seguir mostram como usar políticas do IAM para conceder permissões para o Amazon Kinesis Data Streams para Amazon DynamoDB.

## Exemplo: habilitar o Amazon Kinesis Data Streams para Amazon DynamoDB
<a name="access-policy-kds-example1"></a>

A política do IAM a seguir concede permissões para habilitar o Amazon Kinesis Data Streams para o Amazon DynamoDB na tabela `Music`: Ela não concede permissões para desabilitar, atualizar ou descrever o Kinesis Data Streams para o DynamoDB na tabela `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"
        }
    ]
}
```

------

## Exemplo: Atualizar o Amazon Kinesis Data Streams para o Amazon DynamoDB
<a name="access-policy-kds-example2"></a>

A política do IAM a seguir concede permissões para atualizar o Amazon Kinesis Data Streams para o Amazon DynamoDB na tabela `Music`: Ela não concede permissões para habilitar, desabilitar ou descrever o Amazon Kinesis Data Streams para o Amazon DynamoDB na tabela `Music`. 

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:UpdateKinesisStreamingDestination"
            ],
            "Resource": "arn:aws:dynamodb:us-west-2:111122223333:table/Music"
        }
    ]
}
```

------

## Exemplo: desabilitar o Amazon Kinesis Data Streams para Amazon DynamoDB
<a name="access-policy-kds-example2"></a>

A política do IAM a seguir concede permissões para desabilitar o Amazon Kinesis Data Streams para o Amazon DynamoDB na tabela `Music`: Ela não concede permissões para habilitar, atualizar ou descrever o Amazon Kinesis Data Streams para o Amazon DynamoDB na tabela `Music`. 

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:DisableKinesisStreamingDestination"
            ],
            "Resource": "arn:aws:dynamodb:us-west-2:111122223333:table/Music"
        }
    ]
}
```

------

## Exemplo: aplicar seletivamente permissões para o Amazon Kinesis Data Streams para Amazon DynamoDB com base no recurso
<a name="access-policy-kds-example3"></a>

A política do IAM a seguir concede permissões para habilitar e descrever o Amazon Kinesis Data Streams para o Amazon DynamoDB na tabela `Music` e nega permissões para desabilitar o Amazon Kinesis Data Streams para o Amazon DynamoDB na tabela `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"
        }
    ]
}
```

------

## Usar funções vinculadas ao serviço para o Kinesis Data Streams para DynamoDB
<a name="kds-service-linked-roles"></a>

O Amazon Kinesis Data Streams para Amazon DynamoDB usa [funções vinculadas ao serviço](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-service-linked-role) do AWS Identity and Access Management (IAM). A função vinculada ao serviço é um tipo exclusivo de perfil do IAM vinculada diretamente ao Kinesis Data Streams para DynamoDB. As funções vinculadas a serviços são predefinidas pelo Kinesis Data Streams para DynamoDB e incluem todas as permissões que o serviço requer para chamar outros serviços da AWS em seu nome. 

Uma função vinculada ao serviço facilita a configuração do Kinesis Data Streams para DynamoDB porque você não precisa adicionar as permissões necessárias manualmente. O Kinesis Data Streams para DynamoDB define as permissões de suas funções vinculadas a serviços e, exceto se definido de outra forma, somente o Kinesis Data Streams para DynamoDB pode assumir suas funções. As permissões definidas incluem a política de confiança e a política de permissões, que não pode ser anexada a nenhuma outra entidade do IAM.

Para saber mais sobre outros serviços compatíveis com funções vinculadas a serviços, consulte [Serviços da AWS compatíveis com o IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html) e procure os serviços que contenham **Sim **na coluna **Função vinculada a serviço**. Escolha um **Sim** com um link para visualizar a documentação da função vinculada a esse serviço.

### Permissões de função vinculada ao serviço para o Kinesis Data Streams para DynamoDB
<a name="slr-permissions"></a>

O Kinesis Data Streams para DynamoDB usa a função vinculada ao serviço chamada **AWSServiceRoleForDynamoDBKinesisDataStreamsReplication**. O objetivo dessa função vinculada ao serviço é permitir que o Amazon DynamoDB gerencie a replicação de alterações em nível de item no Kinesis Data Streams em seu nome.

O perfil vinculado ao serviço `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication` confia nos seguintes serviços para aceitar o perfil:
+ `kinesisreplication.dynamodb.amazonaws.com`

A política de permissões da função permite que o Kinesis Data Streams for DynamoDB conclua as seguintes ações nos recursos especificados:
+ Ação: `Put records and describe` em `Kinesis stream`
+ Ação: `Generate data keys` no `AWS KMS` para colocar dados em fluxos do Kinesis que são criptografados usando chaves do AWS KMS geradas pelo usuário.

Para obter o conteúdo exato do documento de política, consulte [DynamoDBKinesisReplicationServiceRolePolicy](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/aws-service-role/DynamoDBKinesisReplicationServiceRolePolicy).

Você deve configurar permissões para que uma entidade do IAM (por exemplo, um usuário, grupo ou função) crie, edite ou exclua um perfil vinculado a serviço. Para saber mais, consulte [Permissões de Função Vinculadas ao Serviço](https://docs.aws.amazon.com/IAM/latest/UserGuide/contributorinsights-service-linked-roles.html#service-linked-role-permissions) no *Guia do Usuário do IAM*.

### Criar uma função vinculada ao serviço para o Kinesis Data Streams para DynamoDB
<a name="create-slr"></a>

Não é necessário criar manualmente uma função vinculada ao serviço. Quando você habilita o Kinesis Data Streams para DynamoDB no Console de gerenciamento da AWS, na AWS CLI ou na API da AWS, o Kinesis Data Streams para DynamoDB cria a função vinculada ao serviço para você. 

Se excluir essa função vinculada ao serviço e precisar criá-la novamente, você poderá usar esse mesmo processo para recriar a função em sua conta. Quando você habilita o Kinesis Data Streams para DynamoDB, o Kinesis Data Streams para DynamoDB cria a função vinculada ao serviço para você. 

### Editar uma função vinculada ao serviço para o Kinesis Data Streams para DynamoDB
<a name="edit-slr"></a>

O Kinesis Data Streams para DynamoDB não permite editar a função vinculada ao serviço `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication`. Depois que criar um perfil vinculado ao serviço, você não poderá alterar o nome do perfil, pois várias entidades podem fazer referência a ele. No entanto, será possível editar a descrição do perfil usando o IAM. Para saber mais, consulte [Editar uma função vinculada a serviço](https://docs.aws.amazon.com/IAM/latest/UserGuide/contributorinsights-service-linked-roles.html#edit-service-linked-role) no *Guia do usuário do IAM*.

### Excluir uma função vinculada ao serviço para o Kinesis Data Streams para DynamoDB
<a name="delete-slr"></a>

Também é possível usar o console do IAM, a AWS CLI ou a API da AWS para excluir manualmente a função vinculada ao serviço. Para isso, primeiro você deve limpar manualmente os recursos de sua função vinculada ao serviço e depois excluí-la manualmente.

**nota**  
Se o serviço Kinesis Data Streams para DynamoDB estiver usando a função quando você tenta excluir os recursos, a exclusão poderá falhar. Se isso acontecer, espere alguns minutos e tente a operação novamente.

**Para excluir manualmente a função vinculada ao serviço usando o IAM**

Use o console do IAM, a AWS CLI ou a API da AWS para excluir a função vinculada ao serviço `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication`. Para obter mais informações, consulte [Excluir uma função vinculada ao serviço](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html) no *Guia do usuário do IAM*.

# Capturar dados de alterações para o DynamoDB Streams
<a name="Streams"></a>

 O DynamoDB Streams captura uma sequência em ordem temporal de modificações em nível de item em qualquer tabela do DynamoDB e armazena essas informações em um log por até 24 horas. As aplicações podem acessar esse log e visualizar os itens de dados à medida que eles aparecem antes e depois de serem modificados, quase em tempo real.

 A criptografia em repouso criptografa os dados em fluxos do DynamoDB. Para obter mais informações, consulte [Criptografia em repouso do DynamoDB](EncryptionAtRest.md).

Um *fluxo do DynamoDB* é um fluxo ordenado de informações sobre alterações em itens de uma tabela do DynamoDB. Quando você habilita um fluxo em uma tabela, o DynamoDB captura informações sobre todas as modificações em itens de dados na tabela.

Sempre que uma aplicação cria, atualiza ou exclui itens nessa tabela, o DynamoDB Streams grava um registro de fluxo com os atributos de chave primária dos itens que foram modificados. Um *registro de fluxo* contém informações sobre uma modificação de dados em um único item de uma tabela do DynamoDB. É possível configurar o stream de modo que os registros de stream capturem informações adicionais, como as imagens "antes" e "depois" de itens modificados.

O DynamoDB Streams ajuda a garantir:
+ Cada registro do fluxo aparece exatamente uma vez no fluxo.
+ Para cada item modificado em uma tabela do DynamoDB, os registros de fluxo aparecem na mesma sequência que as modificações reais no item.

O DynamoDB Streams grava registros de fluxo em tempo quase real para que você possa criar aplicações que consomem esses fluxos e executam ações com base no conteúdo.

**Topics**
+ [Endpoints para DynamoDB Streams](#Streams.Endpoints)
+ [Habilitar um fluxo](#Streams.Enabling)
+ [Ler e processar um fluxo](#Streams.Processing)
+ [DynamoDB Streams e vida útil](time-to-live-ttl-streams.md)
+ [Usar o adaptador do DynamoDB Streams Kinesis Adapter para processar registros de fluxos](Streams.KCLAdapter.md)
+ [API de baixo nível do DynamoDB Streams: exemplo em Java](Streams.LowLevel.Walkthrough.md)
+ [DynamoDB Streams e acionadores do AWS Lambda](Streams.Lambda.md)
+ [DynamoDB Streams e Apache Flink](StreamsApacheFlink.xml.md)

## Endpoints para DynamoDB Streams
<a name="Streams.Endpoints"></a>

AWSO mantém endpoints separados para fluxos do DynamoDB e DynamoDB Streams. Para trabalhar com índices e tabelas de banco de dados, sua aplicação precisa acessar um endpoint do DynamoDB. Para ler e processar registros do DynamoDB Streams, sua aplicação precisa acessar um endpoint do DynamoDB Streams na mesma região.

O DynamoDB Streams oferece dois conjuntos de endpoints. Eles são:
+ **Endpoints somente IPv4**: endpoints com a convenção de nomenclatura `streams.dynamodb.<region>.amazonaws.com`.
+ **Endpoints de pilha dupla**: novos endpoints compatíveis com IPv4 e IPv6 e que seguem a convenção de nomenclatura `streams-dynamodb.<region>.api.aws`.

**nota**  
Para obter uma lista completa de regiões e endpoints do DynamoDB e do DynamoDB Streams, consulte [Regiões e endpoints](https://docs.aws.amazon.com/general/latest/gr/rande.html) na *Referência geral da AWS*.

Os AWS SDKs fornecem clientes separados para o DynamoDB e o DynamoDB Streams. Dependendo das suas necessidades, sua aplicação pode acessar um endpoint do DynamoDB, um endpoint do DynamoDB Streams ou ambos ao mesmo tempo. Para conectar aos dois endpoints, a aplicação precisa instanciar dois clientes, um para o DynamoDB e outro para o DynamoDB Streams.

## Habilitar um fluxo
<a name="Streams.Enabling"></a>

Você pode habilitar um stream em uma nova tabela ao criá-la usando a AWS CLI ou um dos AWS SDKs. Também pode habilitar ou desabilitar um stream em uma tabela existente ou alterar as configurações de um stream. O DynamoDB Streams opera de forma assíncrona e, portanto, não haverá impacto sobre a performance de uma tabela se você habilitar um stream.

A maneira mais fácil de gerenciar o DynamoDB Streams é usar o Console de gerenciamento da AWS.

1. Faça login no Console de gerenciamento da AWS e abra o console do DynamoDB em [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/).

1. No painel do console do DynamoDB, escolha **Tables** (Tabelas) e selecione uma tabela existente.

1. Escolha a guia **Exports and streams** (Exportações e fluxos).

1. Na seção **Detalhes do stream do DynamoDB**, escolha **Ativar**.

1. Na página **Ativar fluxo do DynamoDB**, escolha as informações que serão gravadas no fluxo sempre que os dados da tabela forem modificados:
   + **Key attributes only (Somente atributos de chaves)**: somente os atributos de chaves do item modificado.
   + **New image** (Nova imagem): o item inteiro como é exibido depois de modificado.
   + **Old image** (Imagem antiga): o item inteiro como era exibido antes de modificado.
   + **New and old images** (Imagens nova e antiga): as imagens nova e antiga do item.

   Quando estiver de acordo com as configurações, escolha **Ativar fluxo**.

1. (Opcional) Para desabilitar um fluxo existente, escolha **Desativar** em **Detalhes do stream do DynamoDB**.

Você também pode usar as operações da API `CreateTable` ou `UpdateTable` para habilitar ou modificar um fluxo. O parâmetro `StreamSpecification` determina como o fluxo é configurado:
+ `StreamEnabled`: especifica se um fluxo está habilitado (`true`) ou desabilitado (`false`) para a tabela.
+ `StreamViewType`: especifica as informações que serão gravadas no fluxo sempre que os dados na tabela forem modificados:
  + `KEYS_ONLY`: somente os atributos de chaves do item modificado.
  + `NEW_IMAGE`: o item inteiro como é exibido depois de ser modificado.
  + `OLD_IMAGE`: o item inteiro como era exibido antes de ser modificado.
  + `NEW_AND_OLD_IMAGES`: as imagens nova e antiga do item.

É possível habilitar ou desabilitar um fluxo a qualquer momento. No entanto, você receberá uma `ValidationException` se tentar habilitar um fluxo em uma tabela que já tenha um fluxo. Você também receberá uma `ValidationException` se tentar desabilitar um fluxo em uma tabela que não tenha um fluxo.

Quando você define `StreamEnabled` como `true`, o DynamoDB cria um novo fluxo com um descritor de streaming exclusivo atribuído a ele. Se você desabilitar e reabilitar um fluxo na tabela, será criado um fluxo com um descritor diferente.

Cada fluxo é identificado exclusivamente por um nome do recurso da Amazon (ARN). Veja a seguir um ARN de exemplo para um fluxo em uma tabela do DynamoDB chamada `TestTable`.

```
arn:aws:dynamodb:us-west-2:111122223333:table/TestTable/stream/2015-05-11T21:21:33.291
```

Para determinar o descritor de streaming mais recente de uma tabela, emita uma solicitação `DescribeTable` do DynamoDB e procure o elemento `LatestStreamArn` na resposta.

**nota**  
Não é possível editar um `StreamViewType` após a configuração de um fluxo. Se você precisar fazer alterações em um fluxo depois que ele tiver sido configurado, será necessário desativar o fluxo atual e criar outro.

## Ler e processar um fluxo
<a name="Streams.Processing"></a>

Para ler e processar um fluxo, sua aplicação deve se conectar a um endpoint do DynamoDB Streams e emitir solicitações de API.

Um fluxo consiste em *registros de fluxo*. Cada registro de stream representa uma única modificação de dados na tabela do DynamoDB à qual o fluxo pertence. Cada registro de fluxo recebe um número de sequência, refletindo a ordem em que ele foi publicado no fluxo.

Os registros de fluxo estão organizados em grupos ou *fragmentos*. Cada fragmento atua como um contêiner para vários registros de fluxo e contém informações necessárias para acessar esses registros e fazer iterações neles. Os registros de fluxo em um fragmento são removidos automaticamente depois de 24 horas.

Fragmentos são efêmeros: eles são criados e excluídos automaticamente, conforme necessário. Qualquer fragmento também pode ser dividido em vários novos fragmentos, o que também ocorre automaticamente. (Também é possível que um fragmento pai tenha apenas um fragmento filho.) Um fragmento pode ser dividido em resposta a altos níveis de atividades de gravação em sua tabela principal e, portanto, as aplicações podem processar registros de vários fragmentos em paralelo.

Se você desabilitar um fluxo, todos os fragmentos que estiverem abertos serão fechados. Os dados no stream continuarão legíveis por 24 horas.

Como fragmentos têm uma linhagem (pai e filhos), uma aplicação sempre deverá processar um fragmento pai antes de um fragmento filho. Isso ajuda a garantir que os registros de fluxo também sejam processados na ordem correta. (Se você usa o DynamoDB Streams Kinesis Adapter, isso será feito para você. Sua aplicação processará os fragmentos e os registros de fluxo na ordem correta. Ela manipulará automaticamente fragmentos novos ou expirados, bem como fragmentos que são divididos enquanto a aplicação está em execução. Para obter mais informações, consulte [Usar o adaptador do DynamoDB Streams Kinesis Adapter para processar registros de fluxos](Streams.KCLAdapter.md).)

O diagrama a seguir mostra a relação entre um fluxo, os fragmentos nesse fluxo e os registros de fluxo nesses fragmentos.

![\[Estrutura do DynamoDB Streams. Os registros de fluxo que representam modificações de dados são organizados em fragmentos.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/streams-terminology.png)


**nota**  
Se você executar uma operação `PutItem` ou `UpdateItem` que não altere nenhum dado em um item, o DynamoDB Streams *não* gravará um registro de fluxo para essa operação.

Para acessar um fluxo e processar os registros de fluxo dentro dele, você deve fazer o seguinte:
+ Determinar o ARN exclusivo do fluxo que deseja acessar.
+ Determinar quais fragmentos no fluxo contêm os registros de fluxo desejados.
+ Acessar os fragmentos e recuperar os registros de fluxo desejados.

**nota**  
No máximo dois processos devem estar lendo simultaneamente do mesmo fragmento de fluxo. Ter mais de dois leitores por fragmento pode resultar em controle de utilização.

A API do DynamoDB Streams fornece as seguintes ações para uso por programas de aplicações:
+  `[ListStreams](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_ListStreams.html)`: retorna uma lista de descritores de fluxos para a conta e o endpoint atuais. Opcionalmente, você pode solicitar apenas os descritores de fluxo de um nome de tabela específico.
+ `[DescribeStream](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_DescribeStream.html)`: retorna informações sobre um streaming, incluindo o status atual do streaming, o Nome de recurso da Amazon (ARN), a composição de seus estilhaços e sua tabela correspondente do DynamoDB Você pode opcionalmente usar o campo `ShardFilter` para recuperar o fragmento filho existente associado ao fragmento pai.
+ `[GetShardIterator](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_GetShardIterator.html)`: retorna um *iterador de fragmentos* que descreve um local dentro de um fragmento. Você pode solicitar que o iterador forneça acesso ao ponto mais antigo, o ponto mais novo ou um ponto específico no fluxo.
+ `[GetRecords](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_GetRecords.html)`: retorna os registros do fluxo de um determinado fragmento. Você deve fornecer o iterador de fragmentos retornado de uma solicitação `GetShardIterator`.

Para obter descrições completas dessas operações da API, incluindo solicitações e respostas de exemplo, consulte a [Referência da API do Amazon DynamoDB Streams](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Operations_Amazon_DynamoDB_Streams.html).

### Descoberta de fragmentos
<a name="Streams.ShardDiscovery"></a>



Descubra novos fragmentos em seu stream do DynamoDB com dois métodos poderosos. Como usuário do Amazon DynamoDB Streams, você tem duas maneiras eficazes de rastrear e identificar novos fragmentos:

**Pesquisando toda a topologia do stream**  
Use a API `DescribeStream` para pesquisar regularmente o stream. Isso retorna todos os fragmentos no stream, incluindo novos fragmentos que tenham sido criados. Ao comparar os resultados ao longo do tempo, você pode detectar fragmentos recém-adicionados.

**Descobrindo fragmentos filhos**  
Use a API `DescribeStream` com o parâmetro `ShardFilter` para encontrar um subconjunto de fragmentos. Ao especificar um fragmento pai na solicitação, o DynamoDB Streams retornará seus fragmentos filhos imediatos. Essa abordagem é útil quando você só precisa rastrear a linhagem do fragmento sem escanear todo o stream.   
Os aplicativos que consomem dados do DynamoDB Streams podem fazer a transição eficiente da leitura de um fragmento fechado para seu fragmento filho usando esse parâmetro `ShardFilter`, evitando chamadas repetidas à API `DescribeStream` para recuperar e percorrer o mapa de fragmentos de todos os fragmentos fechados e abertos. Isso ajuda a descobrir rapidamente os fragmentos filhos após o fechamento de um fragmento pai, tornando seus aplicativos de processamento de stream mais responsivos e econômicos.

Ambos os métodos permitem que você fique por dentro da estrutura em evolução do seu DynamoDB Streams, garantindo que você nunca perca atualizações críticas de dados ou modificações de fragmentos.

### Limite de retenção de dados para o DynamoDB Streams
<a name="Streams.DataRetention"></a>

Todos os dados no DynamoDB Streams estão sujeitos a um tempo de vida de 24 horas. É possível recuperar e analisar as atividades das últimas 24 horas de qualquer tabela. No entanto, os dados mais antigos que 24 horas estão suscetíveis a remoção a qualquer momento.

Se você desabilitar um fluxo em uma tabela, os dados nesse fluxo continuarão legíveis por 24 horas. Depois desse tempo, os dados expirarão, e os registros de fluxo serão excluídos automaticamente. Não há nenhum mecanismo para excluir manualmente um fluxo existente. Aguarde até que o limite de retenção expire (24 horas), e todos os registros do fluxo sejam excluídos.

# DynamoDB Streams e vida útil
<a name="time-to-live-ttl-streams"></a>

Você pode fazer backup ou processar os itens excluídos por [vida útil](TTL.md) (TTL) habilitando o Amazon DynamoDB Streams na tabela e processando os registros de fluxos dos itens expirados. Para obter mais informações, consulte [Ler e processar um fluxo](Streams.md#Streams.Processing).

O registro de fluxos contém um campo de identidade do usuário `Records[<index>].userIdentity`.

Os itens excluídos pelo processo de vida útil após a expiração têm os seguintes campos:
+ `Records[<index>].userIdentity.type`

  `"Service"`
+ `Records[<index>].userIdentity.principalId`

  `"dynamodb.amazonaws.com"`

**nota**  
Quando você usa o TTL em uma tabela global, a região em que o TTL foi executado terá o campo `userIdentity` definido. Esse campo não será definido em outras regiões quando a exclusão for replicada.

O JSON a seguir mostra a parte relevante de um único registro de fluxos.

```
"Records": [
    {
        ...

        "userIdentity": {
            "type": "Service",
            "principalId": "dynamodb.amazonaws.com"
        }

        ...

    }
]
```

## Usar o DynamoDB Streams e o Lambda para arquivar itens excluídos do TTL
<a name="streams-archive-ttl-deleted-items"></a>

Combinar a [vida útil (TTL) do DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html), o [DynamoDB Streams](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html) e o [AWS Lambda](https://aws.amazon.com/lambda/) pode ajudar a simplificar os dados de arquivo, reduzir os custos de armazenamento do DynamoDB e diminuir a complexidade do código. O uso do Lambda como consumidor de fluxo oferece muitas vantagens, principalmente a redução de custos em comparação com outros consumidores, como a Kinesis Client Library (KCL). Você não é cobrado por chamadas de API `GetRecords` no fluxo do DynamoDB ao usar o Lambda para consumir eventos, e o Lambda pode fornecer filtragem de eventos por meio da identificação de padrões JSON em um evento de fluxo. Com a filtragem de conteúdo de padrão de evento, é possível definir até cinco filtros diferentes para controlar quais eventos são enviados ao Lambda para processamento. Isso ajuda a reduzir as invocações de suas funções do Lambda, simplifica o código e diminui o custo geral.

Embora o DynamoDB Streams contenha todas as modificações de dados, como as ações `Create`, `Modify` e `Remove`, isso pode resultar em invocações indesejadas da função do Lambda de arquivo. Por exemplo, digamos que você tenha uma tabela com 2 milhões de modificações de dados por hora fluindo para o fluxo, mas menos de 5% delas são exclusões de itens que expirarão no processo de TTL e precisam ser arquivadas. Com [filtros de origem de eventos do Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html), a função do Lambda invocará apenas 100 mil vezes por hora. O resultado da filtragem de eventos é que você é cobrado apenas pelas invocações necessárias, e não pelos 2 milhões de invocações que você teria sem a filtragem de eventos.

A filtragem de eventos é aplicada ao [mapeamento da origem de eventos do Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventsourcemapping.html), que é um recurso que lê com base em um evento escolhido (o fluxo do DynamoDB) e invoca uma função do Lambda. No diagrama a seguir, você pode ver como um item excluído por vida útil é consumido por uma função do Lambda usando fluxos e filtros de eventos.

![\[Um item excluído por meio do processo de TTL inicia uma função do Lambda que usa fluxos e filtros de eventos.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/streams-lambda-ttl.png)


### Padrão de filtro de eventos da vida útil do DynamoDB
<a name="ttl-event-filter-pattern"></a>

A adição do JSON a seguir aos [critérios de filtro](https://docs.aws.amazon.com/lambda/latest/dg/API_FilterCriteria.html) do mapeamento de origem de eventos permite que você invoque sua função do Lambda somente para itens excluídos por TTL:

```
{
    "Filters": [
        {
            "Pattern": { "userIdentity": { "type": ["Service"], "principalId": ["dynamodb.amazonaws.com"] } }
        }
    ]
}
```

### Crie um mapeamento da origem de eventos no AWS Lambda.
<a name="create-event-source-mapping"></a>

Use os trechos de código a seguir para criar um mapeamento de origem de eventos filtrado que você possa conectar ao fluxo do DynamoDB de uma tabela. Cada bloco de código inclui o padrão de filtro de eventos.

------
#### [ 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"]
   }
}
```

------

# Usar o adaptador do DynamoDB Streams Kinesis Adapter para processar registros de fluxos
<a name="Streams.KCLAdapter"></a>

Usar o Amazon Kinesis Adapter é a forma recomendada para consumir fluxos do Amazon DynamoDB. A API do DynamoDB Streams é intencionalmente semelhante à do Kinesis Data Streams. Em ambos os serviços, os fluxos de dados são compostos de fragmentos, os quais são contêineres de registros de stream. Ambas as APIs de serviços contêm as operações `ListStreams`, `DescribeStream`, `GetShards` e `GetShardIterator`. (Embora essas ações do DynamoDB Streams sejam semelhantes às suas equivalentes no Kinesis Data Streams, elas não são 100% idênticas.)

Como um usuário do DynamoDB Streams, você pode utilizar os padrões de design encontrados no KCL para processar fragmentos e registros de fluxos do DynamoDB Streams. Para isso, você pode usar o DynamoDB Streams Kinesis Adapter. O Kinesis Adapter implementa a interface do Kinesis Data Streams para que a KCL possa ser usada para consumir e processar registros do DynamoDB Streams. Para obter instruções sobre como configurar e instalar o DynamoDB Streams Kinesis Adapter, consulte o [repositório do GitHub](https://github.com/awslabs/dynamodb-streams-kinesis-adapter).

Você pode escrever aplicações para Kinesis Data Streams usando a Kinesis Client Library (KCL). A KCL simplifica a codificação fornecendo abstrações úteis acima da API de baixo nível do Kinesis Data Streams. Para obter mais informações sobre a KCL, consulte [Desenvolver consumidores usando a biblioteca de clientes do Kinesis](https://docs.aws.amazon.com/kinesis/latest/dev/developing-consumers-with-kcl.html) no *Guia do desenvolvedor do Amazon Kinesis Data Streams Developer Guide*.

O DynamoDB recomenda usar a KCL versão 3.x com o AWS SDK para Java v2.x. Durante o período de transição, a versão atual do DynamoDB Streams Kinesis Adapter versão 1.x com o AWS SDK para AWS SDK para Java v1.x continuará recebendo suporte total ao longo do ciclo de vida, de acordo com o estabelecido em alinhamento com a [política de manutenção de AWS SDKs e ferramentas](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html).

**nota**  
As versões 1.x e 2.x da Amazon Kinesis Client Library (KCL) estão desatualizadas. A KCL 1.x chegará ao fim do suporte em 30 de janeiro de 2026. É altamente recomendável que você migre suas aplicações de KCL que usam a versão 1.x para a versão mais recente da KCL antes de 30 de janeiro de 2026. Para encontrar a versão mais recente da KCL, consulte a [página da Amazon Kinesis Client Library](https://github.com/awslabs/amazon-kinesis-client) no GitHub. Para ter mais informações sobre as versões mais recentes da KCL, consulte [Use Kinesis Client Library](https://docs.aws.amazon.com/streams/latest/dev/kcl.html).. Para obter mais informações sobre como migrar da KCL 1.x para a KCL 3.x, consulte Migração da KCL 1.x para a KCL 3.x .

O diagrama a seguir mostra como essas bibliotecas interagem entre si.

![\[Interação entre o DynamoDB Streams, o Kinesis Data Streams e o KCL para processar registros do DynamoDB Streams.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/streams-kinesis-adapter.png)


Com o DynamoDB Streams Kinesis Adapter implementado, você pode começar a desenvolver a interface da KCL com as chamadas de API perfeitamente direcionadas no endpoint do DynamoDB Streams.

Quando a aplicação é iniciada, ela chama a KCL para instanciar um operador. Você deve fornecer ao operador informações de configuração da aplicação, como o descritor do fluxo e as credenciais da AWS, além do nome de uma classe de processador de registro que você fornecer. Como ele executa o código no processador de registro, o operador executa as seguintes tarefas:
+ Conecta-se ao stream
+ Enumera os fragmentos no fluxo
+ Verifica e enumera fragmentos filhos de um fragmento pai fechado dentro do fluxo
+ Coordena as associações do estilhaço com outros operadores (se houver)
+ Cria uma instância de um processador de registro para cada fragmento que gerencia
+ Extrai registros do fluxo
+ Escala a taxa de chamadas de API GetRecords quanto há alto throughput (se o modo de recuperação estiver configurado).
+ Envia os registros ao processador de registros correspondente
+ Registros processados pelos pontos de verificação
+ Equilibra as associações de estilhaço-operador quando a contagem de instância de operadores muda
+ Equilibra as associações de fragmento-operador quando os fragmentos se dividem

O adaptador da KCL permite o modo de recuperação, um recurso de ajuste automático da taxa de chamadas para lidar com aumentos temporários de throughput. Quando o atraso no processamento de fluxos excede um limite configurável (padrão: um minuto), o modo de recuperação escala a frequência de chamadas de API GetRecords de acordo com um valor configurável (padrão: três vezes) para recuperar os registros mais depressa e depois volta ao normal quando o atraso diminui. Isso é fundamental durante períodos de alto throughput em que a atividade de gravação do DynamoDB pode sobrecarregar os consumidores usando taxas de sondagem padrão. O modo de recuperação pode ser habilitado por meio do parâmetro de configuração `catchupEnabled` (padrão: false).

**nota**  
Para obter uma descrição dos conceitos da KCL aqui listados, consulte [Desenvolver consumidores usando a biblioteca clientes do Kinesis](https://docs.aws.amazon.com/kinesis/latest/dev/developing-consumers-with-kcl.html) no *Guia do desenvolvedor do Amazon Kinesis Data Streams*.  
Para obter mais informações sobre como usar fluxos com o AWS Lambda, consulte [DynamoDB Streams e acionadores do AWS Lambda](Streams.Lambda.md)

# Migrar da KCL 1.x para a KCL 3.x
<a name="streams-migrating-kcl"></a>

## Visão geral
<a name="migrating-kcl-overview"></a>

Este guia oferece instruções para migrar uma aplicação de consumidor da KCL 1.x para a KCL 3.x. Devido a diferenças de arquitetura entre a KCL 1.x e a KCL 3.x, a migração requer a atualização de vários componentes para garantir compatibilidade.

A KCL 1.x usa classes e interfaces diferentes em comparação com o KCL 3.x. Você deve primeiro migrar o processador de registros, a fábrica do processador de registros e as classes de operador para o formato compatível com a KCL 3.x e seguir as etapas de migração da KCL 1.x para a KCL 3.x.

## Etapas da migração
<a name="migration-steps"></a>

**Topics**
+ [Etapa 1: migrar o processador de registros](#step1-record-processor)
+ [Etapa 2: migrar a fábrica do processador de registros](#step2-record-processor-factory)
+ [Etapa 3: migrar o operador](#step3-worker-migration)
+ [Etapa 4: visão geral e recomendações de configuração da KCL 3.x](#step4-configuration-migration)
+ [Etapa 5: migrar da KCL 2.x para a KCL 3.x](#step5-kcl2-to-kcl3)

### Etapa 1: migrar o processador de registros
<a name="step1-record-processor"></a>

Este exemplo mostra um processador de registros implementado para o DynamoDB Streams Kinesis Adapter da KCL 1.x:

```
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();
        }
    }
}
```

**Como migrar a classe RecordProcessor**

1. Altere as interfaces de `com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor` e `com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IShutdownNotificationAware` para `com.amazonaws.services.dynamodbv2.streamsadapter.processor.DynamoDBStreamsShardRecordProcessor` da seguinte forma:

   ```
   // 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. Atualize as instruções de importação para os métodos `initialize` e `processRecords`.

   ```
   // 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. Substitua o método `shutdownRequested` pelos novos métodos a seguir: `leaseLost`, `shardEnded`, e `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();
           }
       }
   ```

Esta é a versão atualizada da classe de processador de registros:

```
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();
        }
    }
}
```

**nota**  
O DynamoDB Streams Kinesis Adapter agora usa o modelo de registro SDKv2. No SDKv2, objetos `AttributeValue` complexos (`BS`, `NS`, `M`, `L` e `SS`) nunca retornam null. Use os métodos `hasBs()`, `hasNs()`, `hasM()`, `hasL()` e `hasSs()` para verificar se esses valores existem.

### Etapa 2: migrar a fábrica do processador de registros
<a name="step2-record-processor-factory"></a>

A fábrica do processador de registros é responsável por criar processadores de registro quando uma concessão é realizada. Veja o seguinte exemplo de fábrica da 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);
    }
}
```

**Migrar para `RecordProcessorFactory`**
+ Altere a interface implementada de `com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessorFactory` para `software.amazon.kinesis.processor.ShardRecordProcessorFactory` da seguinte forma:

  ```
  // 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() {
  ```

Veja o seguinte exemplo de fábrica de processador de registros em 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();
    }
}
```

### Etapa 3: migrar o operador
<a name="step3-worker-migration"></a>

Na versão 3.0 da KCL, uma nova classe, chamada **Scheduler**, substitui a classe **Worker**. Veja o seguinte exemplo de operador da KCL 1.x:

```
final KinesisClientLibConfiguration config = new KinesisClientLibConfiguration(...)
final IRecordProcessorFactory recordProcessorFactory = new RecordProcessorFactory();
final Worker worker = StreamsWorkerFactory.createDynamoDbStreamsWorker(
        recordProcessorFactory,
        workerConfig,
        adapterClient,
        amazonDynamoDB,
        amazonCloudWatchClient);
```

**Para migrar o operador**

1. Altere a instrução `import` para a classe `Worker` para as instruções de importação para as classes `Scheduler` e `ConfigsBuilder`.

   ```
   // import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker;
   import software.amazon.kinesis.coordinator.Scheduler;
   import software.amazon.kinesis.common.ConfigsBuilder;
   ```

1. Importe `StreamTracker` e altere a importação de `StreamsWorkerFactory` para `StreamsSchedulerFactory`.

   ```
   import software.amazon.kinesis.processor.StreamTracker;
   // import software.amazon.dynamodb.streamsadapter.StreamsWorkerFactory;
   import software.amazon.dynamodb.streamsadapter.StreamsSchedulerFactory;
   ```

1. Escolha a posição por meio da qual iniciar a aplicação. Ela pode ser `TRIM_HORIZON` ou `LATEST`.

   ```
   import software.amazon.kinesis.common.InitialPositionInStream;
   import software.amazon.kinesis.common.InitialPositionInStreamExtended;
   ```

1. Crie uma instância de `StreamTracker`.

   ```
   StreamTracker streamTracker = StreamsSchedulerFactory.createSingleStreamTracker(
           streamArn,
           InitialPositionInStreamExtended.newInitialPosition(InitialPositionInStream.TRIM_HORIZON)
   );
   ```

1. Crie o objeto `AmazonDynamoDBStreamsAdapterClient`.

   ```
   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. Crie o objeto `ConfigsBuilder`.

   ```
   import software.amazon.kinesis.common.ConfigsBuilder;
   
   ...
   ConfigsBuilder configsBuilder = new ConfigsBuilder(
                   streamTracker,
                   applicationName,
                   adapterClient,
                   dynamoDbAsyncClient,
                   cloudWatchAsyncClient,
                   UUID.randomUUID().toString(),
                   new StreamsRecordProcessorFactory());
   ```

1. Crie o `Scheduler` usando `ConfigsBuilder` como mostrado no seguinte exemplo:

   ```
   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
           );
   ```

**Importante**  
A configuração `CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X` mantém a compatibilidade entre o DynamoDB Streams Kinesis Adapter para a KCL v3 e a KCL v1, não entre a KCL v2 e a v3.

### Etapa 4: visão geral e recomendações de configuração da KCL 3.x
<a name="step4-configuration-migration"></a>

Para obter uma descrição detalhada das configurações introduzidas após a KCL 1.x que são relevantes na KCL 3.x, consulte [KCL configurations](https://docs.aws.amazon.com//streams/latest/dev/kcl-configuration.html) e [KCL migration client configuration](https://docs.aws.amazon.com//streams/latest/dev/kcl-migration.html#client-configuration).

**Importante**  
Em vez de criar objetos diretamente de `checkpointConfig`, `coordinatorConfig`, `leaseManagementConfig`, `metricsConfig`, `processorConfig` e `retrievalConfig`, recomendamos usar `ConfigsBuilder` para definir configurações na KCL 3.x e versões posteriores para evitar problemas de inicialização do Agendador. O `ConfigsBuilder` oferece uma maneira mais flexível e sustentável de configurar sua aplicação da KCL.

#### Configurações com valor padrão de atualização na KCL 3.x
<a name="kcl3-configuration-overview"></a>

`billingMode`  
Na KCL versão 1.x, o valor padrão para `billingMode` é definido como `PROVISIONED`. No entanto, na KCL versão 3.x, o padrão `billingMode` é `PAY_PER_REQUEST` (modo sob demanda). Recomendamos que você use o modo de capacidade sob demanda em sua tabela de concessões para ajustar automaticamente a capacidade com base no uso. Para obter orientações sobre como usar a capacidade provisionada para suas tabelas de concessões, consulte [Best practices for the lease table with provisioned capacity mode](https://docs.aws.amazon.com//streams/latest/dev/kcl-migration-lease-table.html).

`idleTimeBetweenReadsInMillis`  
Na KCL versão 1.x, o valor padrão para `idleTimeBetweenReadsInMillis` é definido como 1.000 (ou 1 segundo). A KCL versão 3.x define o valor padrão para i`dleTimeBetweenReadsInMillis` como 1.500 (ou 1,5 segundo), mas o Amazon DynamoDB Streams Kinesis Adapter substitui esse valor padrão, definindo-o como 1.000 (ou 1 segundo).

#### Novas configurações na KCL 3.x
<a name="kcl3-new-configs"></a>

`leaseAssignmentIntervalMillis`  
Essa configuração define o intervalo de tempo antes que os fragmentos recém-descobertos comecem a ser processados, e é calculada como 1,5 × `leaseAssignmentIntervalMillis`. Se essa configuração não for definida explicitamente, o intervalo de tempo será padronizado como 1,5 × `failoverTimeMillis`. O processamento de novos fragmentos exige a verificação da tabela de concessões e a consulta a um índice secundário global (GSI) na tabela de concessões. A redução de `leaseAssignmentIntervalMillis` aumenta a frequência dessas operações de verificação e consulta, aumentando os custos do DynamoDB. Recomendamos definir esse valor como 2 mil (ou 2 segundos) para minimizar o atraso no processamento de novos fragmentos.

`shardConsumerDispatchPollIntervalMillis`  
Essa configuração define o intervalo entre pesquisas sucessivas feitas pelo consumidor do fragmento para acionar transições de estado. Na KCL versão 1.x, esse comportamento era controlado pelo parâmetro `idleTimeInMillis`, que não era exposto como uma definição configurável. Na KCL versão 3.x, recomendamos definir essa configuração para corresponder ao valor usado em ` idleTimeInMillis` na configuração da KCL versão 1.x.

### Etapa 5: migrar da KCL 2.x para a KCL 3.x
<a name="step5-kcl2-to-kcl3"></a>

Para garantir uma transição tranquila e a compatibilidade com a versão mais recente da Kinesis Client Library (KCL), siga as etapas de 5 a 8 nas instruções do guia de migração para [atualizar da KCL 2.x para a KCL 3.x](https://docs.aws.amazon.com//streams/latest/dev/kcl-migration-from-2-3.html#kcl-migration-from-2-3-worker-metrics).

Para solucionar problemas comuns da KCL 3.x, consulte [Troubleshooting KCL consumer applications](https://docs.aws.amazon.com//streams/latest/dev/troubleshooting-consumers.html).

# Reverter para a versão anterior da KCL
<a name="kcl-migration-rollback"></a>

Este tópico explica como reverter sua aplicação de consumidor para a versão anterior da KCL. O processo de reversão consiste em duas etapas:

1. Execute a [Ferramenta de Migração da KCL](https://github.com/awslabs/amazon-kinesis-client/blob/master/amazon-kinesis-client/scripts/KclMigrationTool.py).

1. Reimplante o código da versão anterior da KCL.

## Etapa 1: executar a Ferramenta de Migração da KCL
<a name="kcl-migration-rollback-step1"></a>

Quando precisar reverter para a versão anterior da KCL, você deve executar a Ferramenta de Migração da KCL. Essa ferramenta executa duas tarefas importantes:
+ Ela remove uma tabela de metadados chamada tabela de métricas do operador e o índice secundário global na tabela de concessões no DynamoDB. Esses artefatos são criados pela KCL 3.x, mas não são necessários quando você reverte para a versão anterior.
+ Ela faz com que todos os operadores funcionem em um modo compatível com a KCL 1.x e comecem a usar o algoritmo de balanceamento de carga usado nas versões anteriores da KCL. Se você tiver problemas com o novo algoritmo de balanceamento de carga na KCL 3.x, isso mitigará o problema imediatamente.

**Importante**  
A tabela de estados do coordenador no DynamoDB deve existir e não deve ser excluída durante o processo de migração, reversão e avanço.

**nota**  
É importante que todos os operadores em sua aplicação de consumidor usem o mesmo algoritmo de balanceamento de carga em um determinado momento. A Ferramenta de Migração da KCL garante que todos os operadores em sua aplicação de consumidor da KCL 3.x mudem para o modo compatível com a KCL 1.x para que todos os operadores executem o mesmo algoritmo de balanceamento de carga durante a reversão da aplicação para a versão anterior da KCL.

Você pode baixar a [Ferramenta de Migração da KCL](https://github.com/awslabs/amazon-kinesis-client/blob/master/amazon-kinesis-client/scripts/KclMigrationTool.py) no diretório de scripts do [repositório da KCL no GitHub](https://github.com/awslabs/amazon-kinesis-client/tree/master). Execute o script usando um operador ou host com as permissões apropriadas para gravar na tabela de estados do coordenador, na tabela de métricas do operador e na tabela de concessões. As [permissões do IAM](https://docs.aws.amazon.com/streams/latest/dev/kcl-iam-permissions.html) apropriadas devem estar configuradas para aplicações de consumidor da KCL. Execute o script uma única vez para cada aplicação da KCL usando o comando especificado:

```
python3 ./KclMigrationTool.py --region region --mode rollback [--application_name applicationName] [--lease_table_name leaseTableName] [--coordinator_state_table_name coordinatorStateTableName] [--worker_metrics_table_name workerMetricsTableName]
```

### Parâmetros
<a name="kcl-migration-rollback-parameters"></a>

`--region`  
Substitua *region* pela Região da AWS.

`--application_name`  
Esse parâmetro é obrigatório se você estiver usando nomes padrão para suas tabelas de metadados do DynamoDB (tabela de concessões, tabela de estados do coordenador e tabela de métricas do operador). Se você tiver especificado nomes personalizados para essas tabelas, poderá omitir esse parâmetro. Substitua *applicationName* pelo nome da aplicação da KCL. A ferramenta usa esse nome para obter os nomes de tabela padrão se os nomes personalizados não forem fornecidos.

`--lease_table_name`  
Esse parâmetro é necessário quando você define um nome personalizado para a tabela de concessões na configuração da KCL. Se você estiver usando o nome padrão da tabela, poderá omitir esse parâmetro. Substitua *leaseTableName* pelo nome da tabela personalizada que você especificou para a tabela de concessões.

`--coordinator_state_table_name`  
Esse parâmetro é necessário quando você define um nome personalizado para a tabela de estados do coordenador na configuração da KCL. Se você estiver usando o nome padrão da tabela, poderá omitir esse parâmetro. Substitua *coordinatorStateTableName* pelo nome da tabela personalizada que você especificou para a tabela de estados do coordenador.

`--worker_metrics_table_name`  
Esse parâmetro é necessário quando você define um nome personalizado para a tabela de métricas do operador na configuração da KCL. Se você estiver usando o nome padrão da tabela, poderá omitir esse parâmetro. Substitua *workerMetricsTableName* pelo nome da tabela personalizada que você especificou para a tabela de métricas do operador.

## Etapa 2: reimplantar o código com a versão anterior da KCL
<a name="kcl-migration-rollback-step2"></a>

**Importante**  
Qualquer menção à versão 2.x na saída gerada pela Ferramenta de Migração da KCL deve ser interpretada como sendo a versão 1.x da KCL. A execução do script não realiza uma reversão completa, apenas alterna o algoritmo de balanceamento de carga para o usado na versão 1.x da KCL.

Depois de executar a Ferramenta de Migração da KCL para uma reversão, você verá uma destas mensagens:

Mensagem 1  
“Rollback completed. Your application was running 2x compatible functionality. Please rollback to your previous application binaries by deploying the code with your previous KCL version”.  
**Ação necessária:** isso significa que os operadores estavam executando no modo compatível com a KCL 1.x. Reimplante o código para os operadores com a versão anterior da KCL.

Mensagem 2  
“Rollback completed. Your KCL Application was running 3x functionality and will rollback to 2x compatible functionality. If you don't see mitigation after a short period of time, please rollback to your previous application binaries by deploying the code with your previous KCL version”.  
**Ação necessária:** isso significa que os operadores estavam executando no modo da KCL 3.x e a Ferramenta de Migração da KCL mudou todos os operadores para o modo compatível com a KCL 1.x. Reimplante o código para os operadores com a versão anterior da KCL.

Mensagem 3  
“Application was already rolled back. Any KCLv3 resources that could be deleted were cleaned up to avoid charges until the application can be rolled forward with migration”.  
**Ação necessária:** isso significa que os operadores já foram revertidos para execução no modo compatível com a KCL 1.x. Reimplante o código para os operadores com a versão anterior da KCL.

# Avançar para a KCL 3.x após uma reversão
<a name="kcl-migration-rollforward"></a>

Este tópico explica como avançar sua aplicação de consumidor para a KCL 3.x após uma reversão. Quando precisar avançar, você deve concluir um processo de duas etapas:

1. Execute a [Ferramenta de Migração da KCL](https://github.com/awslabs/amazon-kinesis-client/blob/master/amazon-kinesis-client/scripts/KclMigrationTool.py).

1. Implantar o código com a KCL 3.x.

## Etapa 1: executar a Ferramenta de Migração da KCL
<a name="kcl-migration-rollforward-step1"></a>

Execute a Ferramenta de Migração da KCL com o seguinte comando para avançar para a KCL 3.x:

```
python3 ./KclMigrationTool.py --region region --mode rollforward [--application_name applicationName] [--coordinator_state_table_name coordinatorStateTableName]
```

### Parâmetros
<a name="kcl-migration-rollforward-parameters"></a>

`--region`  
Substitua *region* pela Região da AWS.

`--application_name`  
Esse parâmetro será obrigatório se você estiver usando nomes padrão para a tabela de estados do coordenador. Se você tiver especificado nomes personalizados para a tabela de estados do coordenador, poderá omitir esse parâmetro. Substitua *applicationName* pelo nome da aplicação da KCL. A ferramenta usa esse nome para obter os nomes de tabela padrão se os nomes personalizados não forem fornecidos.

`--coordinator_state_table_name`  
Esse parâmetro é necessário quando você define um nome personalizado para a tabela de estados do coordenador na configuração da KCL. Se você estiver usando o nome padrão da tabela, poderá omitir esse parâmetro. Substitua *coordinatorStateTableName* pelo nome da tabela personalizada que você especificou para a tabela de estados do coordenador.

Após a execução da Ferramenta de Migração no modo de avanço, o KCL cria os seguintes recursos do DynamoDB necessários para a KCL 3.x:
+ Um índice secundário global na tabela de concessões
+ Uma tabela de métricas do operador

## Etapa 2: implantar o código com a KCL 3.x
<a name="kcl-migration-rollforward-step2"></a>

Depois de executar a Ferramenta de Migração da KCL para um avanço, implante seu código com a KCL 3.x nos operadores. Para concluir sua migração, consulte [Step 8: Complete the migration](https://docs.aws.amazon.com/streams/latest/dev/kcl-migration-from-2-3.html#kcl-migration-from-2-3-finish).

# Demonstração: DynamoDB Streams Kinesis Adapter
<a name="Streams.KCLAdapter.Walkthrough"></a>

Esta seção é uma demonstração de uma aplicação em Java que usa a Amazon Kinesis Client Library e o Amazon DynamoDB Streams Kinesis Adapter. A aplicação mostra um exemplo de replicação de dados, no qual as atividades de gravação de uma tabela são aplicadas a uma segunda tabela, com o conteúdo de ambas mantido em sincronia. Para o código-fonte, consulte [Programa completo: DynamoDB Streams Kinesis Adapter](Streams.KCLAdapter.Walkthrough.CompleteProgram.md).

O programa faz o seguinte:

1. Cria duas tabelas do DynamoDB chamadas `KCL-Demo-src` e `KCL-Demo-dst`. Cada uma dessas tabelas tem um fluxo habilitado.

1. Gera atividades de atualização na tabela de origem, adicionando, atualizando e excluindo itens. Isso faz com que os dados sejam gravados no fluxo da tabela.

1. Lê os registros do fluxo, faz a reconstrução desses registros como solicitações do DynamoDB e aplica essas solicitações à tabela de destino.

1. Verifica as tabelas de origem e destino para garantir que o conteúdo seja idêntico.

1. Realiza uma limpeza excluindo as tabelas.

Essas etapas estão descritas nas seções a seguir, e a aplicação completa é mostrada no final do passo-a-passo.

**Topics**
+ [Etapa 1: criar tabelas do DynamoDB](#Streams.KCLAdapter.Walkthrough.Step1)
+ [Etapa 2: gerar atividades de atualização na tabela de origem](#Streams.KCLAdapter.Walkthrough.Step2)
+ [Etapa 3: processar o fluxo](#Streams.KCLAdapter.Walkthrough.Step3)
+ [Etapa 4: garantir que as duas tabelas tenham conteúdo idêntico](#Streams.KCLAdapter.Walkthrough.Step4)
+ [Etapa 5: limpar](#Streams.KCLAdapter.Walkthrough.Step5)
+ [Programa completo: DynamoDB Streams Kinesis Adapter](Streams.KCLAdapter.Walkthrough.CompleteProgram.md)

## Etapa 1: criar tabelas do DynamoDB
<a name="Streams.KCLAdapter.Walkthrough.Step1"></a>

A primeira etapa é criar duas tabelas do DynamoDB: uma de origem e outra de destino. O `StreamViewType` no fluxo da tabela de origem é `NEW_IMAGE`. Isso significa que sempre que um item é modificado nessa tabela, o item “depois” da imagem é gravado no fluxo. Dessa forma, o fluxo mantém o controle de todas as atividades de gravação na tabela.

O exemplo a seguir mostra o código usado para a criação das duas tabelas.

```
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);
```

## Etapa 2: gerar atividades de atualização na tabela de origem
<a name="Streams.KCLAdapter.Walkthrough.Step2"></a>

O próximo passo é gerar algumas atividades de gravação na tabela de origem. Enquanto essas atividades estão ocorrendo, o fluxo da tabela de origem também é atualizado quase em tempo real.

A aplicação define uma classe auxiliar com métodos que chamam as operações da API `PutItem`, `UpdateItem` e `DeleteItem` para gravar os dados. O exemplo de código a seguir mostra como esses métodos são usados.

```
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");
```

## Etapa 3: processar o fluxo
<a name="Streams.KCLAdapter.Walkthrough.Step3"></a>

Agora, o programa inicia o processamento do fluxo. O DynamoDB Streams Kinesis Adapter atua como uma camada transparente entre a KCL e o endpoint do DynamoDB Streams para que o código possa usar totalmente a KCL em vez de precisar fazer chamadas de baixo nível ao DynamoDB Streams. O programa realiza as seguintes tarefas:
+ Ele define uma classe de processador de registro, `StreamsRecordProcessor`, com métodos que estão em conformidade com a definição de interface da KCL: `initialize`, `processRecords` e `shutdown`. O método `processRecords` contém a lógica necessária para leituras do fluxo da tabela de origem e para gravações na tabela de destino.
+ Ele define uma fábrica de classes para a classe de processador de registro (`StreamsRecordProcessorFactory`). Isso é necessário para programas Java que usam a KCL.
+ Ele instancia um novo `Worker` da KCL, que está associado à fábrica de classes.
+ Ele desliga `Worker` quando o processamento do registro é concluído.

Opcionalmente, habilite o modo de recuperação na configuração do adaptador da KCL do Streams para escalar automaticamente a taxa de chamadas de API GetRecords em três vezes (padrão) quando o atraso no processamento de fluxos exceder um minuto (padrão), o que ajuda o consumidor de fluxos a lidar com altos picos de throughput na tabela.

Para saber mais sobre a definição da interface da KCL, consulte [Desenvolvimento de consumidores usando a Amazon Kinesis Client Library](https://docs.aws.amazon.com/kinesis/latest/dev/developing-consumers-with-kcl.html) no *Guia do desenvolvedor do Amazon Kinesis Data Streams*. 

O exemplo de código a seguir mostra o loop principal em `StreamsRecordProcessor`. A instrução `case` determina a ação a ser executada, com base no `OperationType` que aparece no registro de fluxo.

```
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();
        }
    }
}
```

## Etapa 4: garantir que as duas tabelas tenham conteúdo idêntico
<a name="Streams.KCLAdapter.Walkthrough.Step4"></a>

Neste ponto, o conteúdo das tabelas de origem e destino está sincronizado. A aplicação emite solicitações `Scan` em ambas as tabelas para verificar se o conteúdo delas é realmente idêntico.

A classe `DemoHelper` contém um método `ScanTable` que chama a API de `Scan` de baixo nível. O exemplo a seguir mostra como fazer isso.

```
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!");
}
```

## Etapa 5: limpar
<a name="Streams.KCLAdapter.Walkthrough.Step5"></a>

A demonstração está concluída e, portanto, a aplicação exclui as tabelas de origem e destino. Consulte o seguinte exemplo de código. Mesmo depois que as tabelas são excluídas, seus fluxos permanecem disponíveis por até 24 horas. Após esse período, eles serão automaticamente excluídos.

```
dynamoDBClient.deleteTable(new DeleteTableRequest().withTableName(srcTable));
dynamoDBClient.deleteTable(new DeleteTableRequest().withTableName(destTable));
```

# Programa completo: DynamoDB Streams Kinesis Adapter
<a name="Streams.KCLAdapter.Walkthrough.CompleteProgram"></a>

Veja a seguir o programa Java completo que realiza as tarefas descritas em [Demonstração: DynamoDB Streams Kinesis Adapter](Streams.KCLAdapter.Walkthrough.md). Quando executá-lo, você verá uma saída semelhante à seguinte:

```
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.
```

**Importante**  
 Para executar esse programa, verifique se a aplicação cliente tem acesso ao DynamoDB e ao Amazon CloudWatch usando políticas. Para obter mais informações, consulte [Políticas baseadas em identidade para o DynamoDB](security_iam_service-with-iam.md#security_iam_service-with-iam-id-based-policies). 

O código-fonte consiste em quatro arquivos `.java`. Para criar esse programa, adicione a seguinte dependência, que inclui a Amazon Kinesis Client Library (KCL) 3.x e o AWS SDK para Java v2 como dependências temporárias:

------
#### [ 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'
```

------

Os arquivos de origem são:
+ `StreamsAdapterDemo.java`
+ `StreamsRecordProcessor.java`
+ `StreamsRecordProcessorFactory.java`
+ `StreamsAdapterDemoHelper.java`

## StreamsAdapterDemo.java
<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.java
<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.java
<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.java
<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 de baixo nível do DynamoDB Streams: exemplo em Java
<a name="Streams.LowLevel.Walkthrough"></a>

**nota**  
O código nesta página não é completo e não trata todos os cenários de consumo do Amazon DynamoDB Streams. A maneira recomendada de consumir registros de stream do DynamoDB é por meio do Amazon Kinesis Adapter usando a Kinesis Client Library (KCL), conforme descrito em [Usar o adaptador do DynamoDB Streams Kinesis Adapter para processar registros de fluxos](Streams.KCLAdapter.md).

Esta seção contém um programa em Java que mostra o DynamoDB Streams em ação. O programa faz o seguinte:

1. Cria uma tabela do DynamoDB com um fluxo habilitado.

1. Descreve as configurações de fluxo dessa tabela.

1. Modifica os dados na tabela.

1. Descreve os fragmentos no fluxo.

1. Lê os registros de fluxo dos fragmentos.

1. Busca fragmentos filhos e continua lendo os registros.

1. Limpa.

Quando executar o programa, você verá um resultado semelhante ao seguinte:

```
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 Exemplo**  

```
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 e acionadores do AWS Lambda
<a name="Streams.Lambda"></a>

O Amazon DynamoDB é integrado ao AWS Lambda para que você possa criar *acionadores* (trechos de código que respondem automaticamente a eventos no DynamoDB Streams). Com os acionadores, você pode criar aplicações que reagem às modificações de dados em tabelas do DynamoDB.

**Topics**
+ [Tutorial 1: Usar filtros para processar todos os eventos com o Amazon DynamoDB e o AWS Lambda usando a AWS CLI](Streams.Lambda.Tutorial.md)
+ [Tutorial 2: Usar filtros para processar alguns eventos com o DynamoDB e o Lambda](Streams.Lambda.Tutorial2.md)
+ [Práticas recomendadas de uso do DynamoDB Streams com o Lambda](Streams.Lambda.BestPracticesWithDynamoDB.md)

Se você habilitar o DynamoDB Streams em uma tabela, poderá associar o nome do recurso da Amazon (ARN) do fluxo a uma função do AWS Lambda escrita por você. Todas as ações de mutação nessa tabela do DynamoDB poderão então ser capturadas como um item no fluxo. Por exemplo, é possível definir um gatilho para que, quando um item em uma tabela for modificado, um novo registro apareça imediatamente no fluxo dessa tabela. 

**nota**  
Se você inscrever mais de duas funções do Lambda em um fluxo do DynamoDB, poderá ocorrer controle de utilização de leitura.

O serviço [AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html) pesquisa o fluxo em busca de novos registros quatro vezes por segundo. Quando novos registros de fluxo estão disponíveis, a função do Lambda é invocada de maneira síncrona. É possível inscrever até duas funções do Lambda no mesmo fluxo do DynamoDB. Se você inscrever mais de duas funções do Lambda no mesmo fluxo do DynamoDB, poderá ocorrer controle de utilização de leitura.

A função do Lambda pode enviar uma notificação, iniciar uma workflow ou realizar qualquer outra ação especificada. É possível escrever uma função do Lambda para simplificar a cópia de cada registro de fluxo no armazenamento persistente, como o Gateway de Arquivos do Amazon S3 (Amazon S3), e criar uma trilha de auditoria permanente de atividades de gravação na tabela. Ou suponhamos que você tenha um aplicativo de jogos móveis que grava em uma tabela `GameScores`. Sempre que o atributo `TopScore` da tabela `GameScores` é atualizado, um registro de fluxo correspondente é gravado no fluxo da tabela. Este evento poderia, em seguida, acionar uma função do Lambda que posta uma mensagem de felicitações em uma rede de mídia social. Essa função também seria escrita para ignorar quaisquer registros de fluxo que não são atualizações para `GameScores` ou que não modificam o atributo `TopScore`.

Se a sua função retornar um erro, o Lambda tentará executar novamente o lote até que o processamento seja bem-sucedido ou os dados expirem. Você também pode configurar o Lambda para tentar novamente com um lote menor, limitar o número de tentativas, descartar registros quando eles se tornarem muito antigos e outras opções.

Como práticas recomendadas de performance, a função do Lambda precisa ser de curta duração. Para evitar a introdução de atrasos de processamento desnecessários, ela também não deve executar uma lógica complexa. Para um fluxo de alta velocidade em particular, é melhor acionar fluxos de trabalho assíncronos de função de etapa de pós-processamento do que Lambdas síncronos de longa execução.

 É possível usar acionadores do Lambda em diferentes contas da AWS configurando uma política baseada em recursos no fluxo do DynamoDB para conceder acesso de leitura entre contas à função do Lambda. Para saber mais sobre como configurar o fluxo para permitir acesso entre contas, consulte [Compartilhar acesso com funções do AWS Lambda entre contas](rbac-cross-account-access.md#shared-access-cross-acount-lambda) no “Guia do desenvolvedor do DynamoDB”.

Para obter mais informações sobre o AWS Lambda, consulte o [Guia do desenvolvedor do AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/).

# Tutorial 1: Usar filtros para processar todos os eventos com o Amazon DynamoDB e o AWS Lambda usando a AWS CLI
<a name="Streams.Lambda.Tutorial"></a>

 

Neste tutorial, você cria um acionador do AWS Lambda para processar um fluxo de uma tabela do DynamoDB.

**Topics**
+ [Etapa 1: criar uma tabela do DynamoDB com um fluxo habilitado](#Streams.Lambda.Tutorial.CreateTable)
+ [Etapa 2: criar uma função de execução do Lambda](#Streams.Lambda.Tutorial.CreateRole)
+ [Etapa 3: criar um tópico do Amazon SNS](#Streams.Lambda.Tutorial.SNSTopic)
+ [Etapa 4: criar e testar uma função do Lambda](#Streams.Lambda.Tutorial.LambdaFunction)
+ [Etapa 5: criar e testar um acionador](#Streams.Lambda.Tutorial.CreateTrigger)

O cenário deste tutorial é o Woofer, uma rede social simples. Os usuários do Woofer se comunicam usando *barks* (mensagens de texto curtas) que são enviados a outros usuários do Woofer. O diagrama a seguir mostra os componentes e o fluxo de trabalho desse aplicativo.

![\[Fluxo de trabalho da aplicação Woofer de uma tabela do DynamoDB, registro de fluxos, função do Lambda e tópico do Amazon SNS.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/StreamsAndTriggers.png)


1. Um usuário grava um item em uma tabela do DynamoDB (`BarkTable`). Cada item na tabela representa um bark.

1. Um novo registro de fluxo é gravado para refletir que um novo item foi adicionado à `BarkTable`.

1. O novo registro de fluxo aciona uma função do AWS Lambda (`publishNewBark`).

1. Se o registro de fluxo indicar que um novo item foi adicionado à `BarkTable`, a função do Lambda lerá os dados do registro de fluxo e publicará uma mensagem em um tópico no Amazon Simple Notification Service (Amazon SNS).

1. A mensagem é recebida pelos assinantes do tópico do Amazon SNS. (Neste tutorial, o único assinante é um endereço de e-mail.)

**Antes de começar**  
Este tutorial usa a AWS Command Line Interface AWS CLI. Se você ainda não tiver feito isso, siga as instruções de instalação no [Guia do usuário do AWS Command Line Interface](https://docs.aws.amazon.com/cli/latest/userguide/) para instalar e configurar a AWS CLI.

## Etapa 1: criar uma tabela do DynamoDB com um fluxo habilitado
<a name="Streams.Lambda.Tutorial.CreateTable"></a>

Nesta etapa, você cria uma tabela do DynamoDB (`BarkTable`) para armazenar todos os barks dos usuários do Woofer. A chave primária é composta de `Username` (chave de partição) e de `Timestamp` (chave de classificação). Ambos os atributos são do tipo string.

`BarkTable` tem um fluxo habilitado. Mais adiante neste tutorial, você criará um acionador associando uma função do AWS Lambda ao fluxo.

1. Use o seguinte comando para criar a tabela.

   ```
   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. Na saída, procure o `LatestStreamArn`.

   ```
   ...
   "LatestStreamArn": "arn:aws:dynamodb:region:accountID:table/BarkTable/stream/timestamp
   ...
   ```

   Anote a `region` e o `accountID`, pois eles serão necessários para as outras etapas deste tutorial.

## Etapa 2: criar uma função de execução do Lambda
<a name="Streams.Lambda.Tutorial.CreateRole"></a>

Nesta etapa, você cria uma função do AWS Identity and Access Management (IAM) (`WooferLambdaRole`) e atribui permissões a ela. Essa função será usada pela função do Lambda que você cria em [Etapa 4: criar e testar uma função do Lambda](#Streams.Lambda.Tutorial.LambdaFunction). 

Você também cria uma política para a função. A política contém todas as permissões de que a função do Lambda precisa em tempo de execução.

1. Crie um arquivo denominado `trust-relationship.json` com os conteúdos a seguir.

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

****  

   ```
   {
      "Version":"2012-10-17",		 	 	 
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "lambda.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
        }
      ]
    }
   ```

------

1. Insira o seguinte comando para criar a `WooferLambdaRole`.

   ```
   aws iam create-role --role-name WooferLambdaRole \
       --path "/service-role/" \
       --assume-role-policy-document file://trust-relationship.json
   ```

1. Crie um arquivo denominado `role-policy.json` com os conteúdos a seguir. (Substitua `region` e `accountID` por sua região e seu ID de conta da AWS.)

------
#### [ 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": [
                   "*"
               ]
           }
       ]
   }
   ```

------

   A política tem quatro declarações que fornecem permissões à `WooferLambdaRole` para fazer o seguinte:
   + Execute uma função do Lambda (`publishNewBark`). Você cria a função mais adiante neste tutorial.
   + Acesse o Amazon CloudWatch Logs. A função do Lambda grava o diagnóstico no CloudWatch Logs em tempo de execução.
   + Leia os dados do fluxo do DynamoDB para `BarkTable`.
   + Publique mensagens no Amazon SNS.

1. Execute o seguinte comando para anexar a política à função `WooferLambdaRole`.

   ```
   aws iam put-role-policy --role-name WooferLambdaRole \
       --policy-name WooferLambdaRolePolicy \
       --policy-document file://role-policy.json
   ```

## Etapa 3: criar um tópico do Amazon SNS
<a name="Streams.Lambda.Tutorial.SNSTopic"></a>

Nesta etapa, você cria um tópico do Amazon SNS (`wooferTopic`) e inscreve um endereço de e-mail nele. A função do Lambda usa esse tópico para publicar novos barks de usuários do Woofer.

1. Digite o seguinte comando para criar um novo tópico do Amazon SNS.

   ```
   aws sns create-topic --name wooferTopic
   ```

1. Digite o seguinte comando para inscrever um endereço de e-mail no `wooferTopic`. (Substitua `region` e `accountID` por sua região e ID da conta da AWS e substitua `example@example.com` por um endereço de e-mail válido.)

   ```
   aws sns subscribe \
       --topic-arn arn:aws:sns:region:accountID:wooferTopic \
       --protocol email \
       --notification-endpoint example@example.com
   ```

1. O Amazon SNS envia uma mensagem de confirmação ao seu endereço de e-mail. Selecione o link **Confirm subscription** (Confirmar assinatura) na mensagem para concluir o processo de assinatura.

## Etapa 4: criar e testar uma função do Lambda
<a name="Streams.Lambda.Tutorial.LambdaFunction"></a>

Nesta etapa, você cria uma função do AWS Lambda (`publishNewBark`) para processar registros de fluxo da `BarkTable`.

A função `publishNewBark` processa apenas os eventos de fluxo que correspondem a novos itens na `BarkTable`. A função lê dados de um evento como esse e, em seguida, invoca o Amazon SNS; para publicá-lo.

1. Crie um arquivo denominado `publishNewBark.js` com os conteúdos a seguir. (Substitua `region` e `accountID` por sua região e seu ID de conta da AWS.)

   ```
   '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. Crie um arquivo zip para conter `publishNewBark.js`. Se você tiver o utilitário de linha de comando zip, poderá digitar o seguinte comando para fazer isso.

   ```
   zip publishNewBark.zip publishNewBark.js
   ```

1. Ao criar a função do Lambda, você especifica o nome do recurso da Amazon (ARN) da `WooferLambdaRole` que você criou em [Etapa 2: criar uma função de execução do Lambda](#Streams.Lambda.Tutorial.CreateRole). Digite o seguinte comando para recuperar o ARN.

   ```
   aws iam get-role --role-name WooferLambdaRole
   ```

   Na saída, procure o ARN da `WooferLambdaRole`.

   ```
   ...
   "Arn": "arn:aws:iam::region:role/service-role/WooferLambdaRole"
   ...
   ```

   Use o seguinte comando para criar a função do Lambda. Substitua *roleARN* pelo ARN da `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. Agora teste o `publishNewBark` para verificar se ele funciona. Para fazer isso, você deve fornecer informações semelhantes a um registro real do DynamoDB Streams.

   Crie um arquivo denominado `payload.json` com os conteúdos a seguir. Substitua `region` e `accountID` por sua Região da AWS e seu ID de conta.

   ```
   {
       "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"
           }
       ]
   }
   ```

   Use o seguinte comando para testar a função `publishNewBark`.

   ```
   aws lambda invoke --function-name publishNewBark --payload file://payload.json --cli-binary-format raw-in-base64-out output.txt
   ```

   Se o teste for bem-sucedido, você verá a seguinte saída.

   ```
   {
       "StatusCode": 200,
       "ExecutedVersion": "$LATEST"
   }
   ```

   Além disso, o arquivo `output.txt` conterá o seguinte texto.

   ```
   "Successfully processed 1 records."
   ```

   Você também receberá uma nova mensagem de e-mail dentro de alguns minutos.
**nota**  
AWS LambdaO grava informações de diagnóstico no Amazon CloudWatch Logs. Se você encontrar erros em sua função do Lambda, poderá usar essas informações de diagnóstico para fins de solução de problemas:  
Abra o console do CloudWatch em [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).
No painel de navegação, selecione **Logs**.
Escolha o grupo de logs a seguir: `/aws/lambda/publishNewBark`
Escolha o fluxo de logs mais recente para visualizar a saída (e os erros) da função.

## Etapa 5: criar e testar um acionador
<a name="Streams.Lambda.Tutorial.CreateTrigger"></a>

Em [Etapa 4: criar e testar uma função do Lambda](#Streams.Lambda.Tutorial.LambdaFunction), você testou a função do Lambda para garantir que ela fosse executada corretamente. Nesta etapa, você cria um *acionador* associando a função do Lambda (`publishNewBark`) à origem de um evento (o fluxo `BarkTable`).

1. Ao criar o acionador, você deve especificar o ARN do fluxo de `BarkTable`. Digite o seguinte comando para recuperar o ARN.

   ```
   aws dynamodb describe-table --table-name BarkTable
   ```

   Na saída, procure o `LatestStreamArn`.

   ```
   ...
    "LatestStreamArn": "arn:aws:dynamodb:region:accountID:table/BarkTable/stream/timestamp
   ...
   ```

1. Insira o seguinte comando para criar o acionador. Substitua `streamARN` pelo ARN do fluxo atual.

   ```
   aws lambda create-event-source-mapping \
       --region region \
       --function-name publishNewBark \
       --event-source streamARN  \
       --batch-size 1 \
       --starting-position TRIM_HORIZON
   ```

1. Teste o acionador. Insira o seguinte comando para adicionar um item a `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"}
   ```

   Você deve receber uma nova mensagem de e-mail dentro de alguns minutos.

1. Abra o console do DynamoDB e adicione mais alguns itens a `BarkTable`. Você deve especificar valores para os atributos `Username` e `Timestamp`. (Você também deve especificar um valor para `Message`, embora isso não seja obrigatório.) Você deve receber uma nova mensagem de e-mail para cada item que adicionar a `BarkTable`.

   A função do Lambda processa apenas novos itens que você adiciona a `BarkTable`. Se você atualizar ou excluir um item na tabela, a função não fará nada.

**nota**  
O AWS Lambda grava informações de diagnóstico no Amazon CloudWatch Logs. Se você encontrar erros em sua função do Lambda, poderá usar essas informações de diagnóstico para fins de solução de problemas.  
Abra o console do CloudWatch em [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).
No painel de navegação, selecione **Logs**.
Escolha o grupo de logs a seguir: `/aws/lambda/publishNewBark`
Escolha o fluxo de logs mais recente para visualizar a saída (e os erros) da função.

# Tutorial 2: Usar filtros para processar alguns eventos com o DynamoDB e o Lambda
<a name="Streams.Lambda.Tutorial2"></a>

Neste tutorial, você criará um acionador do AWS Lambda para processar somente alguns eventos em um fluxo de uma tabela do DynamoDB.

**Topics**
+ [Reunir todos os componentes: CloudFormation](#Streams.Lambda.Tutorial2.Cloudformation)
+ [Reunir todos os componentes: CDK](#Streams.Lambda.Tutorial2.CDK)

Com a [filtragem de eventos do Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html), é possível utilizar expressões de filtro para controlar quais eventos o Lambda enviará para a função processar. É possível configurar até cinco filtros diferentes por fluxo do DynamoDB. Se você estiver usando janelas em lotes, o Lambda aplicará os critérios de filtro a cada novo evento para determinar se deseja adicioná-lo ao lote atual.

Os filtros são aplicados por meio de estruturas chamadas `FilterCriteria`. Os três principais atributos de `FilterCriteria` são `metadata properties`, `data properties` e `filter patterns`. 

Aqui está um exemplo de estrutura de um evento do 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"
}
```

Essas `metadata properties` são os campos do objeto do evento. No caso dos DynamoDB Streams, as `metadata properties` são campos como o `dynamodb` ou o `eventName`. 

Essas `data properties` são os campos do corpo do evento. Para filtrar as `data properties`, certifique-se de contê-las em `FilterCriteria` dentro da chave adequada. Para fontes de eventos do DynamoDB, a chave de dados é `NewImage` ou `OldImage`.

Por fim, as regras de filtro definirão a expressão de filtro que você deseja aplicar a uma propriedade específica. Veja alguns exemplos:


| Operador de comparação | Exemplo | Sintaxe da regra (parcial) | 
| --- | --- | --- | 
|  Nulo  |  O tipo de produto é nulo  |  `{ "product_type": { "S": null } } `  | 
|  Vazio  |  O nome do produto está vazio  |  `{ "product_name": { "S": [ ""] } } `  | 
|  Igual  |  O estado é igual a Flórida  |  `{ "state": { "S": ["FL"] } } `  | 
|  E  |  O estado do produto é igual à Flórida e a categoria do produto é Chocolate  |  `{ "state": { "S": ["FL"] } , "category": { "S": [ "CHOCOLATE"] } } `  | 
|  Ou  |  O estado do produto é Flórida ou Califórnia  |  `{ "state": { "S": ["FL","CA"] } } `  | 
|  Não  |  O estado do produto não é Flórida  |  `{"state": {"S": [{"anything-but": ["FL"]}]}}`  | 
|  Existe  |  O produto caseiro existe  |  `{"homemade": {"S": [{"exists": true}]}}`  | 
|  Não existe  |  O produto Homemade não existe  |  `{"homemade": {"S": [{"exists": false}]}}`  | 
|  Começa com  |  PK começa com COMPANY  |  `{"PK": {"S": [{"prefix": "COMPANY"}]}}`  | 

É possível especificar até cinco padrões de filtragem de eventos em uma função do Lambda. Observe que cada um desses cinco eventos será avaliado como um OR lógico. Então, se você configurar dois filtros chamados `Filter_One` e `Filter_Two`, a função do Lambda executará `Filter_One` OU `Filter_Two`.

**nota**  
Na página de [filtragem de eventos do Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html), há algumas opções para filtrar e comparar valores numéricos. No entanto, no caso de eventos de filtro do DynamoDB, isso não se aplica porque os números no DynamoDB são armazenados como strings. Por exemplo ` "quantity": { "N": "50" }`, sabemos que é um número por causa da propriedade `"N"`.

## Reunir todos os componentes: CloudFormation
<a name="Streams.Lambda.Tutorial2.Cloudformation"></a>

Para mostrar a funcionalidade de filtragem de eventos na prática, aqui está um exemplo de modelo do CloudFormation. Esse modelo gerará uma tabela simples do DynamoDB com uma chave de partição PK e uma chave de classificação SK com o Amazon DynamoDB Streams habilitado. Ele criará uma função do Lambda e uma função simples de execução do Lambda que permitirá gravar logs no Amazon Cloudwatch e ler os eventos do Amazon DynamoDB Stream. Ele também adicionará o mapeamento da origem do evento entre os DynamoDB Streams e a função do Lambda, para que a função possa ser executada sempre que houver um evento no Amazon DynamoDB Streams.

```
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
```

Depois de implantar esse modelo de formação de nuvem, é possível inserir o seguinte item do Amazon DynamoDB:

```
{
 "PK": "COMPANY#1000",
 "SK": "PRODUCT#CHOCOLATE#DARK",
 "company_id": "1000",
 "type": "",
 "state": "FL",
 "stores": 5,
 "price": 15,
 "quantity": 50,
 "fabric": "Florida Chocolates"
}
```

Graças à função simples do Lambda incluída em linha nesse modelo de formação de nuvem, você verá os eventos nos grupos de logs do Amazon CloudWatch para a função do Lambda da seguinte forma:

```
{
  "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"
}
```

**Exemplos de filtragem**
+ **Somente produtos que correspondam a um determinado estado**

Este exemplo modifica o modelo do CloudFormation para incluir um filtro que corresponda a todos os produtos provenientes da Flórida, com a abreviatura “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
```

Depois de reimplantar a pilha, é possível adicionar o seguinte item do DynamoDB à tabela. Observe que ele não aparecerá nos logs de funções do Lambda, porque o produto neste exemplo é da Califórnia.

```
{
 "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": ""
}
```
+ **Somente os itens que começam com alguns valores em PK e SK**

Este exemplo modifica o modelo do CloudFormation para incluir a seguinte condição:

```
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
```

Observe que a condição AND exige que a condição esteja dentro do padrão, onde as chaves PK e SK estão na mesma expressão separadas por vírgula.

Comece com alguns valores em PK e SK ou de determinado estado.

Este exemplo modifica o modelo do CloudFormation para incluir as seguintes condições:

```
  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
```

Observe que a condição OR é adicionada introduzindo novos padrões na seção de filtro.

## Reunir todos os componentes: CDK
<a name="Streams.Lambda.Tutorial2.CDK"></a>

O exemplo de modelo de formação de projeto CDK a seguir mostra a funcionalidade de filtragem de eventos. Antes de trabalhar com esse projeto de CDK, será preciso [instalar os pré-requisitos](https://docs.aws.amazon.com/cdk/v2/guide/work-with.html), incluindo a [execução de scripts de preparação](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-python.html).

**Criar um projeto de CDK**

Primeiro, crie um novo projeto do AWS CDK, invocando `cdk init` em um diretório vazio.

```
mkdir ddb_filters
cd ddb_filters
cdk init app --language python
```

O comando `cdk init` usa o nome da pasta do projeto para nomear vários elementos do projeto, incluindo classes, subpastas e arquivos. Todos os hifens no nome da pasta são convertidos em sublinhados. Caso contrário, o nome deve seguir a forma de um identificador Python. Por exemplo, ele não deve começar com um número nem conter espaços.

Para trabalhar com o novo projeto, ative o respectivo ambiente virtual. Isso permite que as dependências do projeto sejam instaladas localmente na pasta do projeto, em vez de globalmente.

```
source .venv/bin/activate
python -m pip install -r requirements.txt
```

**nota**  
É possível reconhecer isso como o comando Mac/Linux para ativar um ambiente virtual. Os modelos do Python incluem um arquivo em lote, `source.bat`, que permite que o mesmo comando seja utilizado no Windows. O comando tradicional do Windows `.venv\Scripts\activate.bat` também funciona. Se você inicializou seu projeto do AWS CDK usando o AWS CDK Toolkit v1.70.0 ou anterior, seu ambiente virtual está no diretório `.env` em vez de `.venv`. 

**Infraestrutura base**

Abra o arquivo `./ddb_filters/ddb_filters_stack.py` com o editor de texto de sua preferência. Esse arquivo foi gerado automaticamente quando você criou o projeto do AWS CDK. 

Em seguida, adicione as funções `_create_ddb_table` e `_set_ddb_trigger_function`. Essas funções criarão uma tabela do DynamoDB com a chave de partição PK e a chave de classificação SK no modo de provisionamento sob demanda, com o Amazon DynamoDB Streams habilitado por padrão para mostrar imagens novas e antigas.

A função do Lambda será armazenada na pasta `lambda` abaixo do arquivo `app.py`. Esse arquivo será criado posteriormente. Ele incluirá uma variável de ambiente `APP_TABLE_NAME`, que será o nome da tabela do Amazon DynamoDB criada por essa pilha. Na mesma função, concederemos permissões de leitura de fluxo para a função do Lambda. Por fim, ele se inscreverá no DynamoDB Streams como fonte de eventos para a função do Lambda. 

No final do arquivo no método `__init__`, você chamará as respectivas estruturas para inicializá-las na pilha. Para projetos maiores que exigem componentes e serviços adicionais, talvez seja melhor definir essas estruturas fora da pilha base. 

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

Agora, criaremos uma função do Lambda muito simples que imprimirá os logs no Amazon CloudWatch. Para fazer isso, crie uma pasta chamada `lambda`.

```
mkdir lambda
touch app.py
```

Usando o editor de texto de sua preferência, adicione o seguinte conteúdo ao arquivo `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)
```

Garantindo que você esteja na pasta `/ddb_filters/`, digite o seguinte comando para criar a aplicação de exemplo:

```
cdk deploy
```

Em algum momento, você deverá confirmar se deseja implantar a solução. Aceite as alterações digitando `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
```

Depois que as alterações forem implantadas, abra o console da AWS e adicione um item à tabela. 

```
{
 "PK": "COMPANY#1000",
 "SK": "PRODUCT#CHOCOLATE#DARK",
 "company_id": "1000",
 "type": "",
 "state": "FL",
 "stores": 5,
 "price": 15,
 "quantity": 50,
 "fabric": "Florida Chocolates"
}
```

Os logs do CloudWatch agora devem conter todas as informações dessa entrada. 

**Exemplos de filtragem**
+ **Somente produtos que correspondam a um determinado estado**

Abra o arquivo `ddb_filters/ddb_filters/ddb_filters_stack.py` e modifique-o para incluir o filtro que corresponde a todos os produtos que são iguais a “FL”. Isso pode ser revisado logo abaixo de `event_subscription` na linha 45.

```
event_subscription.add_property_override(
    property_path="FilterCriteria",
    value={
        "Filters": [
            {
                "Pattern": json.dumps(
                    {"dynamodb": {"NewImage": {"state": {"S": ["FL"]}}}}
                )
            },
        ]
    },
)
```
+ **Somente os itens que começam com alguns valores em PK e SK**

Modifique o script Python para incluir a seguinte condição:

```
event_subscription.add_property_override(
    property_path="FilterCriteria",
    value={
        "Filters": [
            {
                "Pattern": json.dumps(
                    {
                        {
                            "dynamodb": {
                                "Keys": {
                                    "PK": {"S": [{"prefix": "COMPANY"}]},
                                    "SK": {"S": [{"prefix": "PRODUCT"}]},
                                }
                            }
                        }
                    }
                )
            },
        ]
    },
```
+ **Comece com alguns valores em PK e SK ou de determinado estado.**

Modifique o script Python para incluir as seguintes condições:

```
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"]}}}}
                )
            },
        ]
    },
)
```

Observe que a condição OR é adicionada incluindo mais elementos à matriz Filters (Filtros).

**Limpeza**

Localize a pilha de filtros na base do diretório de trabalho e execute `cdk destroy`. Confirme a exclusão do recurso:

```
cdk destroy
Are you sure you want to delete: DdbFiltersStack (y/n)? y
```

# Práticas recomendadas de uso do DynamoDB Streams com o Lambda
<a name="Streams.Lambda.BestPracticesWithDynamoDB"></a>

Uma função do AWS Lambda é executada em um *contêiner*, um ambiente de execução isolado de outras funções. Quando você executa uma função pela primeira vez, o AWS Lambda cria um novo contêiner e começa a executar o código da função.

Uma função do Lambda tem um *manipulador* que é executado uma vez por invocação. O manipulador contém a lógica de negócios principal da função. Por exemplo, a função do Lambda mostrada em [Etapa 4: criar e testar uma função do Lambda](Streams.Lambda.Tutorial.md#Streams.Lambda.Tutorial.LambdaFunction) tem um identificador que pode processar registros em um fluxo do DynamoDB. 

Você também pode fornecer o código de inicialização que é executado apenas uma vez: depois que o contêiner é criado, mas antes que o AWS Lambda execute o manipulador pela primeira vez. A função do Lambda mostrada em [Etapa 4: criar e testar uma função do Lambda](Streams.Lambda.Tutorial.md#Streams.Lambda.Tutorial.LambdaFunction) possui um código de inicialização que importa o SDK for JavaScript in Node.js e cria um cliente para o Amazon SNS. Esses objetos devem ser definidos somente uma vez, fora do manipulador.

Depois da execução da função, o AWS Lambda pode optar por reutilizar o contêiner para invocações subsequentes da função. Neste caso, o manipulador da função pode reutilizar os recursos que você definiu no seu código de inicialização. (Você não pode controlar por quanto tempo o AWS Lambda reterá o contêiner, ou se o contêiner será reutilizado.)

Para acionadores do DynamoDB que usam o AWS Lambda, recomendamos o seguinte:
+ AWSOs clientes de serviço da devem ser instanciados no código de inicialização, e não no manipulador. Isso permite que o AWS Lambda reutilize conexões existentes, durante o ciclo de vida do contêiner.
+ Em geral, você não precisa gerenciar explicitamente as conexões ou implementar o pool de conexões porque o AWS Lambda gerencia isso para você.

Um consumidor do Lambda para um fluxo do DynamoDB não garante entrega exatamente uma vez, podendo resultar em duplicações ocasionais. Verifique se o código da função do Lambda é idempotente para evitar que problemas inesperados ocorram devido ao processamento de duplicações.

Para obter mais informações, consulte [Práticas recomendadas para trabalhar com funções do AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html) no *Guia do desenvolvedor do AWS Lambda*.

# DynamoDB Streams e Apache Flink
<a name="StreamsApacheFlink.xml"></a>

É possível consumir registros do Amazon DynamoDB Streams com o Apache Flink. Com o [Amazon Managed Service for Apache Flink](https://aws.amazon.com/managed-service-apache-flink/), é possível transformar e analisar dados de streaming em tempo real usando o Apache Flink. O Apache Flink é um framework de processamento de fluxos de código aberto para processar dados em tempo real. O conector do Amazon DynamoDB Streams para Apache Flink simplifica a criação e o gerenciamento de workloads do Apache Flink e permite que você integre aplicações com outros Serviços da AWS.

O Amazon Managed Service for Apache Flink ajuda você a criar rapidamente aplicações de processamento de fluxos de ponta a ponta para analytics de logs, analytics de clickstream, Internet das Coisas (IoT), tecnologia de anúncios, jogos e muito mais. Os quatro casos de uso mais comuns são extração, transformação e carregamento (ETL) de streaming, aplicações orientadas a eventos, analytics responsivas em tempo real e consultas interativas de fluxos de dados. Para ter mais informações sobre como gravar do Amazon DynamoDB Streams no Apache Flink, consulte [Amazon DynamoDB Streams Connector](https://nightlies.apache.org/flink/flink-docs-master/docs/connectors/datastream/dynamodb/).