

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Programação com o Amazon DocumentDB
<a name="program-docdb"></a>

O serviço oferece suporte à validação do esquema JSON.

**Topics**
+ [Guia de programação em Java do DocumentDB](docdb-java-pg.md)
+ [Usando a validação do esquema JSON](json-schema-validation.md)

# Guia de programação em Java do Amazon DocumentDB
<a name="docdb-java-pg"></a>

Este guia abrangente fornece instruções detalhadas para o trabalho com o Amazon DocumentDB usando os drivers de Java do MongoDB, abordando aspectos essenciais das operações e do gerenciamento do banco de dados.

**Topics**
+ [Introdução](#java-pg-intro)
+ [Pré-requisitos](#java-pg-prereqs)
+ [Modelos de dados](#java-pg-data-models)
+ [Conexão com um driver de Java](java-pg-connect-mongo-driver.md)
+ [Operações CRUD com Java](java-crud-operations.md)
+ [Gerenciamento de índices com Java](index-management-java.md)
+ [Programação orientada a eventos](event-driven-programming.md)

## Introdução
<a name="java-pg-intro"></a>

O guia começa com a conectividade, explicando como estabelecer conexões seguras com clusters do DocumentDB usando o driver de Java do MongoDB. Ele detalha os componentes da cadeia de conexão, a SSL/TLS implementação e várias opções de conexão, incluindo autenticação do IAM e agrupamento de conexões, além de estratégias robustas de tratamento de erros.

Na seção de operações CRUD (criar, ler, atualizar, excluir), o guia aborda detalhadamente a manipulação de documentos, demonstrando como criar, ler, atualizar e excluir documentos usando operações únicas e em massa. Ele explica o uso de filtros, consultas e várias opções de operação, ao mesmo tempo em que enfatiza as melhores práticas para tratamento de erros e implementação da lógica de repetição para melhorar a confiabilidade. O guia também aborda extensivamente o gerenciamento de índices, detalhando a criação e a manutenção de diferentes tipos de índice, incluindo índices de campo único, compostos, esparsos e de texto. Ele explica como otimizar a performance da consulta por meio da seleção adequada do índice e do uso da função `explain()` para analisar os planos de execução da consulta.

A seção final se concentra na programação orientada a eventos usando os fluxos de mudança do Amazon DocumentDB, demonstrando como implementar o monitoramento de alterações de dados em tempo real em aplicações de Java. Ele abrange a implementação de cursores de fluxo de mudança, o manuseio de tokens de retomada para operação contínua e operações baseadas em tempo para processamento de dados históricos. Ao longo do guia, exemplos práticos de código e práticas recomendadas são fornecidos, tornando-o um recurso inestimável para você na criação de aplicações robustas em Java com o Amazon DocumentDB.

## Pré-requisitos
<a name="java-pg-prereqs"></a>

Antes de começar, você deve ter o seguinte:
+ Uma AWS conta com um cluster DocumentDB configurado. Veja esta [postagem no blog de introdução](https://aws.amazon.com/blogs/database/part-1-getting-started-with-amazon-documentdb-using-amazon-ec2/) sobre a configuração do cluster de DocumentDB.
+ O Java Development Kit (JDK) instalado (usaremos o [Amazon Corretto 21](https://docs.aws.amazon.com/corretto/latest/corretto-21-ug/downloads-list.html) para este guia).
+ Maven para o gerenciamento de dependências.

## Modelos de dados para este guia
<a name="java-pg-data-models"></a>

Todo o código de exemplo neste guia pressupõe uma conexão com um banco de dados de teste “ProgGuideData” que tem uma coleção “Restaurantes”. Todos os códigos de amostra neste guia funcionam em um sistema de listagem de restaurantes e, abaixo, há um exemplo da aparência de um documento nesse sistema:

```
{
    "_id": "ab6ad8f119b5bca3efa2c7ae",
    "restaurantId": "REST-CRT9BL",
    "name": "Thai Curry Palace",
    "description": "Amazing Restaurant, must visit",
    "cuisine": "Thai",
    "address": {
        "street": "914 Park Street",
        "city": "Bryan",
        "state": "AL",
        "zipCode": "96865",
        "location": {
            "type": "Point",
            "coordinates": [-25.4619, 8.389]
        }
    },
    "contact": {
        "phone": "(669) 915-9056 x6657"
    },
    "rating": {
        "average": 3.4,
        "totalReviews": 275
    },
    "priceRange": "$",
    "menu": [{
        "category": "Appetizers",
        "items": [{
            "name": "Buffalo Chicken Wings",
            "price": 13.42
        }]
    }],
    "features": [
        "Private Dining"
    ],
    "isActive": false“ michelin”: {“
        star”: 3,
        “ranking_years”: 4
    }
}
```

Todas as amostras de código que mostram ações CRUD, gerenciamento de índices e programação orientada a eventos pressupõem que você tenha um objeto [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoClient.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoClient.html) `dbClient`, um objeto [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoDatabase.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoDatabase.html) `connectionDB` e um objeto [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoCollection.html#find()](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoCollection.html#find()) `collection`.

**nota**  
Todos os exemplos de código neste guia foram testados com o driver de Java versão 5.3.0 do MongoDB.

# Conexão com o Amazon DocumentDB com um driver de Java do MongoDB
<a name="java-pg-connect-mongo-driver"></a>

Esta seção fornece um step-by-step guia para se conectar ao Amazon DocumentDB usando drivers Java. Isso fará com que você comece a integrar o DocumentDB às suas aplicações de Java.

**Topics**
+ [Etapa 1: configurar o projeto do](#step1-set-up)
+ [Etapa 2: criação da string de conexão](#step2-create-connection-string)
+ [Etapa 3: escrita do código de conexão](#step3-write-connect-code)
+ [Etapa 4: tratamento de exceções de conexão](#step4-handle-connect-exceptions)
+ [Etapa 5: execução do código](#step5-running-code)
+ [Práticas recomendadas de conexão](#java-connect-best-practices)

## Etapa 1: configurar o projeto do
<a name="step1-set-up"></a>

1. Usando o Maven, crie um projeto de java:

   ```
   mvn archetype:generate -DgroupId=com.docdb.guide -DartifactId=my-docdb-project -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
   ```

1. Adicione o driver de Java do MongoDB como uma dependência para o projeto em seu arquivo 'pom.xml':

   ```
   <dependency>
       <groupId>org.mongodb</groupId>
       <artifactId>mongodb-driver-sync</artifactId> 
       <version>5.3.0</version> 
   </dependency>
   ```

## Etapa 2: criação da string de conexão
<a name="step2-create-connection-string"></a>

A string de conexão do Amazon DocumentDB é essencial para estabelecer uma conexão entre sua aplicação e seu cluster do DocumentDB. Essa string encapsula informações cruciais, como o endpoint do cluster, a porta, os detalhes de autenticação e várias opções de conexão. Para criar uma string do DocumentDB, você normalmente começa com o formato básico:

```
"mongodb://username:password@cluster-endpoint:port/?[connection options]"
```

Você precisará substituir “nome de usuário” e “senha” por suas credenciais reais. Você pode encontrar o endpoint e o número da porta do seu cluster no Console de gerenciamento da AWS e por meio do AWS CLI. Consulte [Localizar os endpoints de um cluster](db-cluster-endpoints-find.md) para encontrar o endpoint de cluster para o seu cluster. A porta 27017 é a porta padrão para o DocumentDB.

**Exemplos de cadeias de conexão**
+ Estabelecimento de uma conexão com o DocumentDB usando criptografia em trânsito com garantia de que as solicitações de leitura sejam enviadas para réplicas de leitura e gravem no primário:

  ```
  "mongodb://username:password@cluster-endpoint:27017/?tls=true& 
     tlsCAFile=global-bundle.pem& 
     readPreference=secondaryPreferred&
     retryWrites=false"
  ```
+ Estabelecimento de uma conexão com o DocumentDB usando a autenticação do IAM:

  ```
  "mongodb://cluster-endpoint:27017/?tls=true& 
     tlsCAFile=global-bundle.pem& 
     readPreference=secondaryPreferred&
     retryWrites=false&
     authSource=%24external&
     authMechanism=MONGODB-AWS"
  ```

As diferentes opções disponíveis para a string de conexão são as seguintes:
+ [certificado TLS](#connection-string-tls)
+ [Leitura de réplicas de leitura](#connection-string-read-rep)
+ [Preocupação com a gravação e diário](#connection-string-write-journal)
+ [RetryWrites](#connection-string-retry-writes)
+ [Autenticação do IAM](#connection-string-iam-auth)
+ [Grupo de conexões](#connection-string-pool)
+ [Parâmetros de tempo limite da conexão](#connection-string-timeout)

### certificado TLS
<a name="connection-string-tls"></a>

**`tls=true|false`**: esta opção habilita ou desabilita o Transport Layer Security (TLS). Por padrão, a criptografia em trânsito está habilitada no cluster do Amazon DocumentDB e, portanto, a menos que o TLS esteja desabilitado no nível do cluster, o valor dessa opção deve ser `true`.

Ao usar o TLS, o código precisa fornecer um certificado SSL ao criar uma conexão com um cluster do DocumentDB. Baixe o certificado necessário para fazer a conexão segura com o cluster: [https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem](https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem). Há duas formas de usar o arquivo `global-bundle.pem`.
+ **Opção 1**: extraia todos os certificados do arquivo `global-bundle.pem` e use a ferramenta de chave do Java para armazená-los em um arquivo `.jks` que possa ser usado posteriormente no código. Consulte a guia Java em [Conectar-se com o TLS habilitado](connect_programmatically.md#connect_programmatically-tls_enabled) para ver o script que mostra como fazer isso.
+ **Opção 2**: adicione dinamicamente o arquivo `global-bundle.pem` no código, crie um armazenamento de chaves na memória e use `SSLContext` para fornecer o certificado como parte da conexão.

### Leitura de réplicas de leitura
<a name="connection-string-read-rep"></a>

**`replicaSet=rs0&readPreference=secondaryPreferred`**: a especificação dessas duas opções encaminha todas as solicitações de leitura para as réplicas de leitura e as solicitações de gravação para a instância primária. O uso de `replicaSet=rs0` na string de conexão permite que o driver do MongoDB mantenha uma visão atualizada automaticamente da topologia do cluster, permitindo que as aplicações mantenham a visibilidade das configurações atuais dos nós à medida que as instâncias são adicionadas ou removidas. Não fornecer essas opções ou especificar `readPreference=primary` envia todas as leituras e gravações para a instância primária. Para obter mais opções para `readPreference`, consulte [Opções de preferência de leitura](how-it-works.md#durability-consistency-isolation).

### Preocupação com a gravação e diário
<a name="connection-string-write-journal"></a>

A preocupação com a gravação determina o nível de reconhecimento solicitado do banco de dados para operações de gravação. Os drivers do MongoDB oferecem uma opção para ajustar os arquivos de preocupação com a gravação e de diário. O Amazon DocumentDB não espera que você defina a preocupação com a gravação e o diário e ignora os valores enviados para `w` e `j` (`writeConcern` e `journal`). O DocumentDB sempre grava dados com `writeConcern`: `majority` e `journal`: `true` para que as gravações sejam realizadas de forma durável na maioria dos nós antes de enviar uma confirmação para o cliente.

### RetryWrites
<a name="connection-string-retry-writes"></a>

**`retryWrites=false`**: o DocumentDB não oferece suporte a gravações que possam ser repetidas e, portanto, esse atributo sempre deve ser definido como `false`.

### Autenticação do IAM
<a name="connection-string-iam-auth"></a>

**`authSource=%24external`e `authMechanism=MONGODB-AWS`** — Esses dois parâmetros são usados para autenticar usando AWS Identity and Access Management. A autenticação do IAM está disponível no momento somente na versão 5.0 do cluster baseado em instâncias. Para obter mais informações, consulte [Autenticação usando identidade do IAM](iam-identity-auth.md).

### Grupo de conexões
<a name="connection-string-pool"></a>

Essas opções estão disponíveis para agrupamento de conexões:
+ **`maxPoolSize`**: define o número máximo de conexões que podem ser criadas no grupo. Quando todas as conexões estão em uso e uma nova solicitação é recebida, ela espera que uma conexão fique disponível. O padrão para drivers de Java do MongoDB é 100.
+ **`minPoolSize`**: indica o número mínimo de conexões que devem ser mantidas no grupo o tempo todo. O padrão para drivers de Java do MongoDB é 0.
+ **`maxIdleTimeMS`**: determina por quanto tempo uma conexão pode permanecer inativa no grupo antes de ser fechada e removida. O padrão para drivers de Java do MongoDB é de 100 milissegundos.
+ **`waitQueueTimeoutMS`**: configura o tempo de espera de um thread para que uma conexão fique disponível quando o grupo estiver em seu tamanho máximo. Se uma conexão não ficar disponível dentro desse período, será lançada uma exceção. O valor padrão para drivers de Java do MongoDB é de 120.000 milissegundos (2 minutos).

### Parâmetros de tempo limite da conexão
<a name="connection-string-timeout"></a>

O tempo limite é um mecanismo para limitar a quantidade de tempo que uma operação ou tentativa de conexão pode levar até que seja considerada falha. Os parâmetros de tempo limite a seguir estão disponíveis para evitar esperas indefinidas e gerenciar a alocação de recursos:
+ **`connectTimeoutMS`**: configura o tempo de espera do driver para estabelecer uma conexão com o cluster. O padrão é 10.000 milissegundos (10 segundos).
+ **`socketTimeoutMS`**: especifica quanto tempo o driver aguardará por uma resposta do servidor para uma operação de não gravação. O padrão é de 0 (sem tempo limite ou infinito).
+ **`serverSelectionTimeoutMS`**: especifica quanto tempo o driver esperará para encontrar um servidor disponível no cluster. O valor padrão dessa configuração é de 30 segundos e é suficiente para que uma nova instância primária seja eleita durante o failover.

## Etapa 3: escrita do código de conexão
<a name="step3-write-connect-code"></a>

O exemplo de código a seguir mostra como fazer uma conexão de TLS com o Amazon DocumentDB:
+ Ele cria os objetos de Java [https://docs.oracle.com/javase/8/docs/api/java/security/KeyStore.html](https://docs.oracle.com/javase/8/docs/api/java/security/KeyStore.html) e [`SSLContext`>](https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLContext.html).
+ Ele também cria o objeto [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/MongoClientSettings.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/MongoClientSettings.html) ao passá-lo para o objeto [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/ConnectionString.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/ConnectionString.html). Para fazer a conexão de TLS, você deve usar o objeto `MongoClientSettings` para vincular a `connectionstring` e o `sslcontext`.
+ O uso de [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoClients.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoClients.html) obtém um objeto [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoClient.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoClient.html).

```
public static MongoClient makeDbConnection(String dbName, String DbUserName, String DbPassword,
    String DbClusterEndPoint, String keyStorePass) throws Exception {
    MongoClient connectedClient;
    String connectionOptions = "?replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false";
    String connectionUrl = "mongodb://" + DbUserName + ":" + DbPassword + "@" + DbClusterEndPoint + ":27017/" +
        dbName + connectionOptions;

    try {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        try (FileInputStream fis = new FileInputStream("src/main/resources/certs/truststore.jks")) {
            trustStore.load(fis, keyStorePass.toCharArray());
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(trustStore);

            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
            ConnectionString connectionString = new ConnectionString(connectionUrl);
            MongoClientSettings settings = MongoClientSettings.builder()
                .applyConnectionString(connectionString)
                .applyToSslSettings(builder - > {
                    builder.enabled(true);
                    builder.context(sslContext);
                })
                .build();
            connectedClient = MongoClients.create(settings);
        }
        return connectedClient;
    } catch (MongoException e5) {
        throw new RuntimeException(e5);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
```

## Etapa 4: tratamento de exceções de conexão
<a name="step4-handle-connect-exceptions"></a>

Ao trabalhar com o DocumentDB em aplicações de Java, tratar exceções de conexão é crucial para manter operações de banco de dados robustas e confiáveis. Gerenciando adequadamente, essas exceções não apenas ajudam a diagnosticar problemas rapidamente, mas também garantem que sua aplicação possa tratar interrupções temporárias na rede ou indisponibilidade do servidor, melhorando a estabilidade e a experiência do usuário. Algumas das exceções críticas relacionadas ao estabelecimento de conexão incluem:
+ **`MongoException`**: uma exceção geral, pode ser emitida em vários cenários não cobertos por exceções mais específicas. Certifique-se de que essa exceção seja tratada após todas as outras exceções específicas, pois essa é uma exceção geral do MongoDB que captura tudo.
+ **`MongoTimeoutException`**: emitida quando uma operação expira. Por exemplo, ao consultar um endpoint de cluster inexistente.
+ **`MongoSocketException`**: emitida para problemas relacionados à rede. Por exemplo, em uma desconexão repentina da rede durante uma operação. 
+ **`MongoSecurityException`**: emitida quando a autenticação falha. Por exemplo, ao conectar-se com credenciais incorretas. 
+ **`MongoConfigurationException`**: emitida quando há um erro na configuração do cliente. Por exemplo, com o uso de uma string de conexão inválida.

## Etapa 5: execução do código
<a name="step5-running-code"></a>

O exemplo de código a seguir cria uma conexão do Amazon DocumentDB e imprime todos os bancos de dados:

```
public static void TestConnection() {
    try (MongoClient mongoClient = makeDbConnection(DATABASE_NAME, DB_USER_NAME, DB_PASSWORD, DB_CLUSTER_ENDPOINT, KEYSTORE_PASSWORD)) {
        List < String > databases = mongoClient.listDatabaseNames().into(new ArrayList < > ());
        System.out.println("Databases: " + databases);
    } catch (MongoException e) {
        System.err.println("MongoDB error: " + e.getMessage());
        throw new RuntimeException(e);
    }
}
```

## Práticas recomendadas de conexão
<a name="java-connect-best-practices"></a>

A seguir estão as práticas recomendadas a serem consideradas ao se conectar ao Amazon DocumentDB com um driver de Java do MongoDB:
+ Sempre feche o seu [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoClient.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoClient.html) quando não precisar mais que o cliente libere recursos.
+ Trate as exceções de forma adequada e implemente o log de erros adequado.
+ Use variáveis de ambiente ou AWS Secrets Manager para armazenar informações confidenciais, como nomes de usuário e senhas.

# Execução de operações CRUD no Amazon DocumentDB com Java
<a name="java-crud-operations"></a>

Esta seção discute a execução da operação CRUD (criar, ler, atualizar, excluir) no Amazon DocumentDB usando drivers de Java do MongoDB.

**Topics**
+ [Criação e inserção de documentos em uma coleção do DocumentDB](#creating-inserting)
+ [Leitura e recuperação de dados de uma coleção do DocumentDB](#reading-retrieving)
+ [Atualização de documentos existentes em uma coleção do DocumentDB](#updating-documents)
+ [Remoção de documentos de uma coleção do DocumentDB](#deleting-documents)
+ [Tratamento de erros com lógica de novas tentativas](#error-handling)

## Criação e inserção de documentos em uma coleção do DocumentDB
<a name="creating-inserting"></a>

A inserção de documentos no Amazon DocumentDB permite que você adicione novos dados às suas coleções. Há várias maneiras de realizar inserções, dependendo das suas necessidades e do volume de dados com os quais você esteja trabalhando. O método mais básico para inserir um documento individual na coleção é `insertOne()`. Para inserir vários documentos ao mesmo tempo, é possível usar o método `insertMany()`, que permite adicionar uma matriz de documentos em uma única operação. Outro método para inserir muitos documentos em uma coleção do DocumentDB é o `bulkWrite()`. Neste guia, discutimos todos esses métodos para criar documentos em uma coleção do DocumentDB.

**`insertOne()`**

Vamos começar examinando como inserir um documento individual em uma coleção do Amazon DocumentDB. A inserção de um único documento é realizada usando o método `insertOne()`. Esse método usa a [BsonDocument](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/bson/org/bson/BsonDocument.html)para inserção e retorna um [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/result/InsertOneResult.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/result/InsertOneResult.html)objeto que pode ser usado para obter a ID do objeto do novo documento inserido. O código de exemplo abaixo mostra a inserção de um documento de restaurante na coleção:

```
Document article = new Document()
    .append("restaurantId", "REST-21G145")
    .append("name", "Future-proofed Intelligent Bronze Hat")
    .append("cuisine", "International")
    .append("rating", new Document()
        .append("average", 1.8)
        .append("totalReviews", 267))
    .append("features", Arrays.asList("Outdoor Seating", "Live Music"));

try {
    InsertOneResult result = collection.insertOne(article);
    System.out.println("Inserted document with the following id: " + result.getInsertedId());
} catch (MongoWriteException e) {
    // Handle duplicate key or other write errors
    System.err.println("Failed to insert document: " + e.getMessage());
    throw e;
} catch (MongoException e) {
    // Handle other MongoDB errors
    System.err.println("MongoDB error: " + e.getMessage());
    throw e;
}
```

Ao usar `insertOne()`, certifique-se de incluir o tratamento adequado de erros. Por exemplo, no código acima, “`restaurantId`” tem um índice exclusivo e, portanto, executar esse código novamente gerará a `MongoWriteException` a seguir:

```
Failed to insert document: Write operation error on server docdbCluster.docdb.amazonaws.com:27017. 
Write error: WriteError{code=11000, message='E11000 duplicate key error collection: Restaurants index: restaurantId_1', details={}}.
```

**insertMany()**

Os principais métodos usados para inserir muitos documentos em uma coleção são insertMany() e `bulkWrite()`. 

O método `insertMany()` é a maneira mais simples de inserir vários documentos em uma única operação. Ele aceita uma lista de documentos e os insere na coleção. Esse método é ideal quando você insere um lote de novos documentos que são independentes uns dos outros e não exigem nenhum processamento especial ou operações mistas. O código a seguir mostra a leitura de documentos JSON de um arquivo e a inserção deles na coleção. A `insertMany()` função retorna um [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/result/InsertManyResult.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/result/InsertManyResult.html)`InsertManyResult`objeto que pode ser usado para obter todos os documentos inseridos. IDs 

```
// Read JSON file content
String content = new String(Files.readAllBytes(Paths.get(jsonFileName)));
JSONArray jsonArray = new JSONArray(content);

// Convert JSON articles to Documents
List < Document > restaurants = new ArrayList < > ();
for (int i = 0; i < jsonArray.length(); i++) {
    JSONObject jsonObject = jsonArray.getJSONObject(i);
    Document doc = Document.parse(jsonObject.toString());
    restaurants.add(doc);
}
//insert documents in collection
InsertManyResult result = collection.insertMany(restaurants);

System.out.println("Count of inserted documents: " + result.getInsertedIds().size());
```

**[https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/bulk/package-summary.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/bulk/package-summary.html)**

O método `bulkWrite()` permite realizar várias operações de gravação (inserir, atualizar, excluir) em um único lote. É possível usar `bulkWrite()` quando precisar realizar diferentes tipos de operações em um único lote, como inserir alguns documentos e atualizar outros. `bulkWrite()` oferece suporte a dois tipos de gravação em lote, ordenada e não ordenada:
+ *Operações ordenadas*: (padrão) o Amazon DocumentDB processa as operações de gravação sequencialmente e para no primeiro erro encontrado. Isso é útil quando a ordem das operações é importante, como quando as operações posteriores dependem das anteriores. No entanto, as operações ordenadas geralmente são mais lentas do que as operações não ordenadas. Com as operações ordenadas, você deve resolver o caso em que o lote é interrompido no primeiro erro, potencialmente deixando algumas operações sem processamento.
+ *Operações não ordenadas*: permite que o Amazon DocumentDB processe inserções como uma única execução no banco de dados. Se ocorrer um erro com um documento, a operação continuará com os documentos restantes. Isso é particularmente útil quando você insere grandes quantidades de dados e pode tolerar algumas falhas, como durante a migração de dados ou importações em massa, em que alguns documentos podem falhar devido a chaves duplicadas. Com operações não ordenadas, você deve abordar cenários de sucesso parcial em que algumas operações obtêm êxito e outras falham.

Ao trabalhar com o método `bulkWrite()`, algumas classes essenciais são necessárias. Primeiro, a classe [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/WriteModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/WriteModel.html) serve como classe base para todas as operações de gravação e com implementações específicas como [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/InsertOneModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/InsertOneModel.html), [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/UpdateOneModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/UpdateOneModel.html), [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/UpdateManyModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/UpdateManyModel.html), [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/DeleteOneModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/DeleteOneModel.html) e [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/DeleteManyModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/DeleteManyModel.html) tratando diferentes tipos de operações.

A [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/BulkWriteOptions.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/BulkWriteOptions.html)classe é necessária para configurar o comportamento de operações em massa, como definir a ordered/unordered execução ou ignorar a validação de documentos. A classe [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/bulk/BulkWriteResult.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/bulk/BulkWriteResult.html) fornece informações detalhadas sobre os resultados da execução, incluindo contagens de documentos inseridos, atualizados e excluídos.

Para o tratamento de erros, a classe [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/MongoBulkWriteException.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/MongoBulkWriteException.html) é crucial, pois contém informações sobre quaisquer falhas durante a operação em massa, enquanto a classe [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/bulk/BulkWriteError.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/bulk/BulkWriteError.html) fornece detalhes específicos sobre falhas de operação individuais. O código a seguir mostra um exemplo de inserção de uma lista de documentos, bem como atualização e exclusão de um único documento, tudo dentro da execução de uma única chamada ao método `bulkWrite()`. O código também mostra como trabalhar com [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/BulkWriteOptions.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/BulkWriteOptions.html) e [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/bulk/BulkWriteResult.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/bulk/BulkWriteResult.html), bem como o tratamento adequado de erros da operação `bulkWrite()`. 

```
List < WriteModel < Document >> bulkOperations = new ArrayList < > ();
// get list of 10 documents representing 10 restaurants
List < Document > restaurantsToInsert = getSampleData();

for (Document doc: restaurantsToInsert) {
    bulkOperations.add(new InsertOneModel < > (doc));
}
// Update operation
bulkOperations.add(new UpdateOneModel < > (
    new Document("restaurantId", "REST-Y2E9H5"),
    new Document("", new Document("stats.likes", 20))
    .append("", new Document("rating.average", 4.5))));
// Delete operation
bulkOperations.add(new DeleteOneModel < > (new Document("restaurantId", "REST-D2L431")));

// Perform bulkWrite operation
try {
    BulkWriteOptions options = new BulkWriteOptions()
        .ordered(false); // Allow unordered inserts

    BulkWriteResult result = collection.bulkWrite(bulkOperations, options);

    System.out.println("Inserted: " + result.getInsertedCount());
    System.out.println("Updated: " + result.getModifiedCount());
    System.out.println("Deleted: " + result.getDeletedCount());
} catch (MongoBulkWriteException e) {
    System.err.println("Bulk write error occurred: " + e.getMessage());
    // Log individual write errors
    for (BulkWriteError error: e.getWriteErrors()) {
        System.err.printf("Error at index %d: %s (Code: %d)%n", error.getIndex(), error.getMessage(),
            error.getCode());

        // Log the problematic document
        Document errorDoc = new Document(error.getDetails());
        if (errorDoc != null) {
            System.err.println("Problematic document: " + errorDoc);
        }
    }
} catch (Exception e) {
    System.err.println("Error during bulkWrite: " + e.getMessage());
}
```

**Gravações que podem ser repetidas**

Diferentemente do MongoDB, o Amazon DocumentDB não oferece suporte a gravações que possam ser repetidas. Como resultado, você deve implementar uma lógica de repetição personalizada em suas aplicações, especialmente para lidar com problemas de rede ou indisponibilidade temporária de serviços. Uma estratégia de repetição bem implementada geralmente envolve aumentar o atraso entre as tentativas e limitar o número total de tentativas. Consulte [Tratamento de erros com lógica de novas tentativas](#error-handling) abaixo para obter um exemplo de código de criação de lógica de repetição com tratamento de erros.

## Leitura e recuperação de dados de uma coleção do DocumentDB
<a name="reading-retrieving"></a>

A consulta de documentos no Amazon DocumentDB gira em torno de vários componentes principais que permitem recuperar e manipular dados com precisão. O [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoCollection.html#find()](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoCollection.html#find())método é a consulta fundamental APIs nos drivers Java do MongoDB. Ele permite a recuperação de dados complexa com várias opções para filtrar, classificar e projetar resultados. Além do método `find()`, [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/Filters.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/Filters.html) e [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/FindIterable.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/FindIterable.html) são dois outros componentes fundamentais que fornecem os blocos de construção para operações de consulta nos drivers de Java do MongoDB.

A classe `Filters` é uma classe utilitária no driver de Java do MongoDB que fornece uma API fluente para criar filtros de consulta. Essa classe oferece métodos estáticos de fábrica que criam instâncias de objetos `Bson` que representam várias condições de consulta. Os métodos mais usados incluem `eq()` para comparações de igualdade `gt()`, `lt()`, `gte()` e `lte()` para comparações numéricas, `and()` e `or()` para a combinação de várias condições, `in()` e `nin()` para testes de associação de matrizes e `regex()` para correspondência de padrões. A classe foi projetada para ser segura para tipos e fornece melhor verificação de tempo de compilação em comparação com consultas brutas baseadas em documentos, tornando-a a abordagem preferida para criar consultas DocumentDB em aplicações de Java. O tratamento de erros é robusto, com claras exceções lançadas para construções de filtro inválidas.

`FindIterable` é uma interface especializada projetada para lidar com o resultado do método `find()`. Ela fornece um rico conjunto de métodos para refinar e controlar a execução de consultas, oferecendo uma API fluente para o encadeamento de métodos. A interface inclui métodos essenciais de modificação de consultas, como `limit()` para a restrição do número de documentos retornados, `skip()` para paginação, `sort()` para ordenação de resultados, `projection()` para a seleção de campos específicos e `hint()` para a seleção de índices. As operações de lote, ignorar e limitar em `FindIterable` são ferramentas essenciais de paginação e gerenciamento de dados que ajudam a controlar como os documentos são recuperados e processados do banco de dados.

O agrupamento em lotes (`batchSize`) controla quantos documentos o DocumentDB retorna ao cliente em uma única viagem de ida e volta à rede. Quando você define um tamanho de lote, o DocumentDB não retorna todos os documentos correspondentes de uma só vez, mas os retorna em grupos do tamanho de lote especificado. 

Ignorar permite que você desvie o ponto de partida de seus resultados, basicamente dizendo ao DocumentDB que pule um número específico de documentos antes de começar a retornar as correspondências. Por exemplo, `skip(20)` ignorará os primeiros 20 documentos correspondentes. Isso é comumente usado em cenários de paginação em que você deseja recuperar páginas subsequentes de resultados. 

O limite restringe o número total de documentos que podem ser retornados de uma consulta. Quando você especifica `limit(n)`, o DocumentDB deixará de retornar documentos depois de retornar 'n' documentos, mesmo que haja mais correspondências no banco de dados. 

`FindIterable` oferece suporte a padrões de iterador e cursor ao recuperar documentos do Amazon DocumentDB. A vantagem de usar `FindIterable` como iterador é que ela permite o carregamento lento de documentos e só busca documentos quando solicitada pela aplicação. Outro benefício de usar o iterador é que você não é responsável por manter a conexão com o cluster e, portanto, nenhum fechamento explícito da conexão é necessário. 

`FindIterable` também fornece suporte ao [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoCursor.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoCursor.html), que permite que padrões de cursor sejam usados ao trabalhar com consultas do Amazon DocumentDB. O `MongoCursor` é uma implementação específica do driver de Java do MongoDB que fornece controle sobre as operações do banco de dados e o gerenciamento de recursos. Ele implementa a `AutoCloseable` interface, permitindo o gerenciamento explícito de recursos por meio de try-with-resources blocos, o que é crucial para fechar adequadamente as conexões do banco de dados e liberar recursos do servidor. Por padrão, o cursor expira em 10 minutos e o DocumentDB não oferece a opção de alterar esse comportamento de tempo limite. Ao trabalhar com dados em lote, certifique-se de recuperar o próximo lote de dados antes que o cursor atinja o tempo limite. Uma consideração importante ao usar o `MongoCursor` é que ele requer um fechamento explícito para evitar vazamentos de recursos.

Nesta seção, vários exemplos são apresentados para `find()`, `Filters` e `FindIterable`.

O exemplo de código a seguir mostra como usar `find()` para recuperar um único documento usando o campo “restaurantId”:

```
Document filter = new Document("restaurantId", "REST-21G145");
Document result = collection.find(filter).first();
```

Embora o uso de `Filters` permita uma melhor verificação de erros no tempo de compilação, o driver de java também permite que você especifique um filtro `Bson` diretamente no método `find()`. O código de exemplo a seguir passa o documento `Bson` para `find()`:

```
result = collection.find(new Document("$and", Arrays.asList(
    new Document("rating.totalReviews", new Document("$gt", 1000)),
    new Document("priceRange", "$$"))))
```

O código de exemplo a seguir mostra vários exemplos de uso da classe `Filters` com `find()`:

```
FindIterable < Document > results;

// Exact match
results = collection.find(Filters.eq("name", "Thai Curry Palace"));

// Not equal
results = collection.find(Filters.ne("cuisine", "Thai"));

// find an element in an array
results = collection.find(Filters.in("features", Arrays.asList("Private Dining")));

// Greater than
results = collection.find(Filters.gt("rating.average", 3.5));

// Between (inclusive)
results = collection.find(Filters.and(
    Filters.gte("rating.totalReviews", 100),
    Filters.lte("rating.totalReviews", 200)));
// AND
results = collection.find(Filters.and(
    Filters.eq("cuisine", "Thai"),
    Filters.gt("rating.average", 4.5)));

// OR
results = collection.find(Filters.or(
    Filters.eq("cuisine", "Thai"),
    Filters.eq("cuisine", "American")));


// All document where the Field exists
results = collection.find(Filters.exists("michelin"));

// Regex
results = collection.find(Filters.regex("name", Pattern.compile("Curry", Pattern.CASE_INSENSITIVE)));

// Find all document where the array contain the list of value regardless of its order
results = collection.find(Filters.all("features", Arrays.asList("Private Dining", "Parking")));

// Array size
results = collection.find(Filters.size("features", 4));
```

O exemplo a seguir mostra como encadear as operações de `sort()`, `skip()`, `limit()` e `batchSize()` em um objeto `FindIterable`. A ordem de como essas operações são fornecidas influenciará a performance da sua consulta. Como prática recomendada, a ordem dessas operações deve ser `sort()`, `projection()`, `skip()`, `limit()` e `batchSize()`.

```
FindIterable < Document > results = collection.find(Filters.gt("rating.totalReviews", 1000))
    // Sorting
    .sort(Sorts.orderBy(
        Sorts.descending("address.city"),
        Sorts.ascending("cuisine")))
    // Field selection
    .projection(Projections.fields(
        Projections.include("name", "cuisine", "priceRange"),
        Projections.excludeId()))

    // Pagination
    .skip(20)
    .limit(10)
    .batchSize(2);
```

O exemplo de código a seguir mostra como criar um iterador em `FindIterable`. Ele usa a construção `forEach` do Java para percorrer o conjunto de resultados.

```
collection.find(Filters.eq("cuisine", "American")).forEach(doc -> System.out.println(doc.toJson()));
```

No último exemplo de código de `find()`, ele mostra como usar `cursor()` para a recuperação de documentos. Ele cria o cursor no bloco try, o que garante que o cursor seja fechado quando o código sair do bloco try.

```
try (MongoCursor < Document > cursor = collection.find(Filters.eq("cuisine", "American"))
    .batchSize(25)
    .cursor()) {
    while (cursor.hasNext()) {
        Document doc = cursor.next();
        System.out.println(doc.toJson());
    }
} // Cursor automatically closed
```

## Atualização de documentos existentes em uma coleção do DocumentDB
<a name="updating-documents"></a>

O Amazon DocumentDB fornece mecanismos flexíveis e poderosos para modificar documentos existentes e inserir novos quando eles não existam. O driver de Java do MongoDB oferece vários métodos para atualizações: `updateOne()` para atualizações de um único documento, `updateMany()` para atualizações de vários documentos e `replaceOne()` para a substituição completa de documentos. Além desses três métodos, [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/Updates.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/Updates.html), [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/UpdateOptions.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/UpdateOptions.html) e [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/result/UpdateResult.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/result/UpdateResult.html) são outros componentes fundamentais que fornecem os blocos de construção para operações de atualização nos drivers de Java do MongoDB. 

A classe `Updates` no driver de Java do MongoDB é uma classe utilitária que fornece métodos estáticos de fábrica para criar operadores de atualização. Ela serve como o principal construtor para construir operações de atualização de maneira segura e legível. Métodos básicos como `set()`, `unset()`, e `inc()` permitem a modificação direta dos documentos. O poder dessa classe se torna evidente ao combinar várias operações usando o método `Updates.combine()`, que permite que várias operações de atualização sejam executadas atomicamente, garantindo a consistência de dados.

`UpdateOptions` é uma classe de configuração poderosa no driver de Java do MongoDB, que fornece recursos essenciais de personalização para operações de atualização de documentos. Dois aspectos importantes dessa classe são fornecer suporte a filtros upsert e de matriz para operações de atualização. O recurso upsert, ativado por meio de `upsert(true)`, permite a criação de novos documentos quando nenhum documento correspondente for encontrado durante uma operação de atualização. Por meio de `arrayFilters()`, a operação de atualização pode atualizar com precisão os elementos da matriz que atendem a critérios específicos.

`UpdateResult` no driver de Java do MongoDB, fornece o mecanismo de feedback detalhando o resultado de uma operação de atualização. Essa classe encapsula três métricas principais: o número de documentos correspondidos pelos critérios de atualização (`matchedCount`), o número de documentos realmente modificados (`modifiedCount`) e informações sobre quaisquer documentos que sofreram upsert (`upsertedId`). Compreender essas métricas é essencial para o tratamento adequado de erros, a verificação das operações de atualização e a manutenção da consistência de dados nas aplicações.

### Atualização e substituição de um único documento
<a name="update-single-doc"></a>

No DocumentDB, a atualização de um único documento pode ser realizada usando o método updateOne(). Esse método usa um parâmetro de filtro, geralmente fornecido pela classe `Filters`, para identificar o documento a ser atualizado, um parâmetro `Updat`e que determina quais campos devem ser atualizados e um parâmetro `UpdateOptions` opcional para definir opções diferentes para a atualização. O uso do método `updateOne()` atualizará somente o primeiro documento que corresponda aos critérios de seleção. O código de exemplo a seguir atualiza um único campo de um documento:

```
collection.updateOne(Filters.eq("restaurantId", "REST-Y2E9H5"),
    Updates.set("name", "Amazing Japanese sushi"));
```

Para atualizar vários campos em um documento, use `updateOne()` com `Update.combine()` conforme mostrado no exemplo a seguir. O exemplo também mostra como adicionar um item a uma matriz no documento.

```
List<Bson> updates = new ArrayList<>();
// Basic field updates
updates.add(Updates.set("name", "Shanghai Best"));
// Array operations
updates.add(Updates.addEachToSet("features", Arrays.asList("Live Music")));
// Counter updates
updates.add(Updates.inc("rating.totalReviews", 10));
// Combine all updates
Bson combinedUpdates = Updates.combine(updates);
// Execute automic update with one call
collection.updateOne(Filters.eq("restaurantId","REST-1J83NH"), combinedUpdates);
```

O exemplo de código a seguir demonstra como atualizar um documento no banco de dados. Se o documento especificado não existir, a operação o inserirá automaticamente como um novo documento. Esse código também mostra como usar as métricas disponíveis por meio do objeto `UpdateResult`.

```
Bson filter = Filters.eq("restaurantId", "REST-0Y9GL0");
Bson update = Updates.set("cuisine", "Indian");
// Upsert operation
UpdateOptions options = new UpdateOptions().upsert(true);
UpdateResult result = collection.updateOne(filter, update, options);

if (result.getUpsertedId() != null) {
   	System.out.println("Inserted document with _id: " + result.getUpsertedId());
} else {
    	System.out.println("Updated " + result.getModifiedCount() + " document(s)");
}
```

O exemplo de código a seguir demonstra como substituir completamente um documento existente por um novo usando o método `replaceOne()`, em vez de atualizar campos individuais. O método `replaceOne()` sobrescreve o documento inteiro, preservando somente o campo `_id` do original. Se vários documentos corresponderem aos critérios do filtro, somente o primeiro documento encontrado será substituído.

```
Document newDocument = new Document()
                .append("restaurantId", "REST-0Y9GL0")
                .append("name", "Bhiryani Adda")
                .append("cuisine", "Indian")
                .append("rating", new Document()
                        .append("average", 4.8)
                        .append("totalReviews", 267))
                .append("features", Arrays.asList("Outdoor Seating", "Live Music"));

UpdateResult result = collection.replaceOne(
                    Filters.eq("restaurantId", "REST-0Y9GL0"),
                    newDocument);
System.out.printf("Modified %d document%n", result.getModifiedCount());
```

### Atualização de vários documentos
<a name="update-multiple-docs"></a>

Há duas maneiras de atualizar vários documentos em uma coleção simultaneamente. É possível usar o método `updateMany()` ou usar [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/UpdateManyModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/UpdateManyModel.html) com o método `bulkWrite()`. O método `updateMany()` usa um parâmetro de filtro para selecionar documentos para atualização, o parâmetro `Update` para identificar os campos a serem atualizados e um parâmetro `UpdateOptions` opcional para especificar as opções de atualização.

O exemplo de código a seguir demonstra o uso do método `updateMany()`:

```
Bson filter = Filters.and(
    Filters.in("features", Arrays.asList("Private Dining")),
    Filters.eq("cuisine", "Thai"));
UpdateResult result1 = collection.updateMany(filter, Updates.set("priceRange", "$$$"));
```

O exemplo de código a seguir demonstra o método `bulkWrite()` usando a mesma atualização:

```
BulkWriteOptions options = new BulkWriteOptions().ordered(false);
List < WriteModel < Document >> updates = new ArrayList < > ();
Bson filter = Filters.and(
    Filters.in("features", Arrays.asList("Private Dining")),
    Filters.eq("cuisine", "Indian"));
Bson updateField = Updates.set("priceRange", "$$$");
updates.add(new UpdateManyModel < > (filter, updateField));
BulkWriteResult result = collection.bulkWrite(updates, options);
System.out.printf("Modified %d document%n", result.getModifiedCount());
```

## Remoção de documentos de uma coleção do DocumentDB
<a name="deleting-documents"></a>

O driver de Java do MongoDB oferece `deleteOne()` para a remoção de um único documento e `deleteMany()` para a remoção de vários documentos que correspondam a critérios específicos. Assim como a atualização, a operação de exclusão também pode ser usada com o método `bulkWrite()`. Tanto `deleteOne()` quanto `deleteMany()` retornam um objeto [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/result/DeleteResult.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/result/DeleteResult.html) que fornece informações sobre o resultado da operação, incluindo a contagem de documentos excluídos. A seguir há um exemplo de uso de `deleteMany()` para a remoção de vários documentos:

```
Bson filter = Filters.and(
    Filters.eq("cuisine", "Thai"),
    Filters.lt("rating.totalReviews", 50));
DeleteResult result = collection.deleteMany(filter);
System.out.printf("Deleted %d document%n", result.getDeletedCount());
```

## Tratamento de erros com lógica de novas tentativas
<a name="error-handling"></a>

Uma estratégia robusta de tratamento de erros para o Amazon DocumentDB deve implementar a categorização dos erros em passíveis de nova tentativa (como tempos limite de rede, problemas de conexão) e não passíveis de nova tentativa (como falhas de autenticação, consultas inválidas). Para falhas de operação devido a erros que devem ter nova tentativa, ele deve implementar um intervalo de tempo entre cada nova tentativa, bem como o máximo de tentativas de repetição. As operações CRUD devem estar em um bloco try-catch que capture [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/MongoException.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/MongoException.html) e suas subclasses. Além disso, ele deve incluir monitoramento e registro de erros para visibilidade operacional. Veja a seguir um exemplo de código que mostra como implementar o tratamento de erros com nova tentativa:

```
int MAX_RETRIES = 3;
int INITIAL_DELAY_MS = 1000;
int retryCount = 0;

while (true) {
    try {
        crud_operation(); //perform crud that will throw MongoException or one of its subclass
        break;
    } catch (MongoException e) {
        if (retryCount < MAX_RETRIES) {
            retryCount++;
            long delayMs = INITIAL_DELAY_MS * (long) Math.pow(2, retryCount - 1);
            try {
                TimeUnit.MILLISECONDS.sleep(delayMs);
            } catch (InterruptedException t) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Retry interrupted", t);
            }
            continue;
        } else
            throw new RuntimeException("Crud operation failed", e);
    }
}
```

# Gerenciamento de índices no Amazon DocumentDB com Java
<a name="index-management-java"></a>

Os índices permitem a recuperação eficiente de dados de uma coleção do Amazon DocumentDB. Sem índices, o DocumentDB deve digitalizar todos os documentos da coleção para retornar resultados que satisfaçam uma determinada consulta. Este tópico fornece informações sobre como criar, eliminar e listar índices usando os drivers de Java do MongoDB. Ele também discute como determinar se um índice específico está sendo usado na consulta e como dar dicas ao Amazon DocumentDB para usar um índice específico.

**Topics**
+ [Criar índices](#creating-indexes)
+ [Reduzir índices](#dropping-indes)
+ [Determinação da seleção do índice e fornecimento de dicas de índice](#w2aac43b9b7c17c13)

O Amazon DocumentDB oferece suporte a vários tipos de índices. Para obter uma visão geral abrangente de todos os índices com suporte, consulte esta [postagem do blog](https://aws.amazon.com/blogs/database/how-to-index-on-amazon-documentdb-with-mongodb-compatibility/). 

## Criação de índices com Java
<a name="creating-indexes"></a>

Há dois mecanismos para criar índices no Amazon DocumentDB usando drivers de Java do MongoDB: por meio de `runCommand()` e pelo método `createIndex()` para um único índice ou pelo método `createIndexes()` para vários índices. Um motivo para usar os métodos `createIndex()` e `createIndexes()` é que é possível criar um melhor tratamento de erros detectando erros específicos relacionados à criação do índice. Outro motivo para usar esses métodos em vez de `runCommand()` é que o driver de Java do MongDB fornece um rico conjunto de classes de suporte para criação e manipulação de índices. Observe que essas classes de suporte só poderão ser usadas quando você estiver usando os métodos `createIndex()` ou `createIndexes()`. Há três classes de apoio:
+ **[https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/Indexes.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/Indexes.html)**: esta classe serve como uma classe utilitária que oferece métodos estáticos de fábrica para criar vários tipos de índices. Ela simplifica o processo de criação de definições de índice complexas e é comumente usada em conjunto com outras classes relacionadas a índices.
+ **[https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexModel.html)**: esta é uma classe fundamental que encapsula a definição das chaves de índice e suas opções. Ela representa uma especificação completa do índice, combinando o que indexar (as chaves) com a forma de indexar (as opções). Essa classe é particularmente útil ao criar vários índices simultaneamente, pois permite definir uma coleção de especificações de índice que podem ser passadas para o método `createIndexes()`.
+ **[https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexOptions.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexOptions.html)**: esta é uma classe de configuração abrangente que fornece um rico conjunto de métodos para personalizar o comportamento do índice. Ela inclui configurações para índices exclusivos, índices esparsos, tempo de expiração (TTL) e expressões de filtro parcial. Por meio do encadeamento de métodos, é possível configurar várias opções, como a criação de índice em segundo plano e restrições exclusivas.

**Criação de um índice único**

Este exemplo mostra como criar um índice único usando o método `createIndex(` em segundo plano. Para entender a criação de índices em segundo plano e em primeiro plano, consulte [Tipos de criação de índice](managing-indexes.md#index-build-types). O exemplo de código a seguir usa [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexOptions.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexOptions.html) para criar um índice exclusivo com o nome “unique\$1restaurantId\$1idx” em segundo plano. Esse objeto `IndexOptions` é então passado ao método `createIndex()`.

```
collection.createIndex(
    Indexes.ascending("restaurantId"),
    new IndexOptions()
        .unique(true)
        .name("unique_restaurantId_idx")
        .background(true));
```

**Criação de vários índices**

Este exemplo cria vários índices usando o método `createIndexes()`. Primeiro, ele cria a opção para cada índice usando o objeto [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexModel.html) e, em seguida, passa uma lista de objetos `IndexModel` para o método `createIndexes()`. O exemplo de código a seguir mostra como criar um índice composto usando a classe de utilitários [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/Indexes.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/Indexes.html). Essa classe também é usada para especificar se você deseja criar um índice usando a ordem de classificação crescente ou decrescente. Depois de criar vários índices, ele verifica a criação do índice chamando o método `listIndexes()`.

```
// Single Field Index on cuisine
IndexModel singleIndex = new IndexModel(
    Indexes.ascending("cuisine"),
    new IndexOptions().name("cuisine_idx"));

// Compound Index
IndexModel compoundIndex = new IndexModel(
    Indexes.compoundIndex(
        Indexes.ascending("address.state"),
        Indexes.ascending("priceRange")),
    new IndexOptions().name("location_price_idx"));

// Build a list of IndexModel for the indexes
List < IndexModel > indexes = Arrays.asList(
    singleIndex,
    compoundIndex
);

collection.createIndexes(indexes);

// Verify created indexes
collection.listIndexes().forEach(index - > System.out.println("Created index: " + index.toJson()));
```

**Criação de índices esparsos e parciais**

Este exemplo mostra a criação de um índice esparso e um parcial com a criação de um [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexModel.html) para cada tipo de índice.

```
// Sparse Index Model, this will identify only those documents that have a
// michelin star rating
IndexModel sparseIndex = new IndexModel(
    Indexes.ascending("michelin.star"),
    new IndexOptions()
    .name("michelin_sparse_idx")
    .sparse(true));

// Partial Index Model where the restaurant is active and has a rating of 4 and above
IndexModel partialIndex = new IndexModel(
    Indexes.ascending("rating.average"),
    new IndexOptions()
    .name("high_rated_active_idx")
    .partialFilterExpression(
        Filters.and(
            Filters.eq("isActive", true),
            Filters.gte("rating.average", 4.0))));
```

**Criação de um índice de texto**

Este exemplo mostra como criar e excluir um índice de texto. Somente um índice de texto é permitido em uma coleção, mas esse índice de texto pode ser um índice composto cobrindo vários campos. Ao usar vários campos no índice de texto, você também pode atribuir pesos a cada um dos campos no índice. Não há suporte para os índices de texto em campos de matriz no Amazon DocumentDB e, embora você possa usar até 30 campos no índice de texto composto, somente três campos podem receber um peso.

```
IndexModel textIndex = new IndexModel(
    new Document()
    .append("name", "text")
    .append("description", "text")
    .append("cuisine", "text"),
    new IndexOptions()
    .name("restaurant_text_idx")
    .weights(new Document()
        .append("name", 10) // Restaurant name gets highest weight
        .append("description", 5) // Description get medium weight
        .append("cuisine", 2) // Cuisine type gets low weight
    ));

collection.createIndex(textIndex.getKeys(), textIndex.getOptions());
```

**Criação de um índice por meio de `runCommand()`**

O Amazon DocumentDB oferece suporte à criação de índices paralelos para diminuir o tempo necessário para criar índices. A indexação paralela usa vários trabalhadores simultâneos. Os trabalhadores padrão usados para a criação do índice são dois. Esta [postagem do blog](https://aws.amazon.com/blogs/database/unlock-the-power-of-parallel-indexing-in-amazon-documentdb/) fornece uma discussão aprofundada sobre indexação paralela. Atualmente, os drivers de Java do MongDB não oferecem suporte à especificação da opção do trabalhador quando você estiver usando `createIndex()` ou `createIndexes()` e, portanto, a única maneira de especificar trabalhadores é por meio de `runCommand`. O exemplo de código a seguir demonstra como usar `runCommand` para criar um índice que aumente o trabalhador para quatro:

```
Document command = new Document("createIndexes", "Restaurants")
    .append("indexes", Arrays.asList(
        new Document("key", new Document("name", 1))
        .append("name", "restaurant_name_idx")
        .append("workers", 4) // Specify number of workers
    ));

Document commendResult = connectedDB.runCommand(command);
```

## Reduzir índices
<a name="dropping-indes"></a>

O driver de Java do MongoDB fornece vários métodos para eliminar índices, atendendo a diferentes cenários e às suas preferências. É possível eliminar índices por nome, por especificação de chave ou eliminar todos os índices de uma só vez. Os métodos `dropIndex()` e `dropIndexes()` podem ser invocados em um objeto de coleção para eliminar um índice. Ao descartar um índice pelo nome, você deverá garantir que eles usem o nome correto, o que nem sempre é intuitivo, especialmente para índices compostos ou gerados automaticamente. A tentativa de eliminar um índice inexistente resultará em uma [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/MongoCommandException.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/MongoCommandException.html). O índice `default _id` não pode ser descartado, pois garante a exclusividade do documento na coleção.

O exemplo de código a seguir mostra como eliminar um índice fornecendo o nome do campo em que o índice foi criado ou excluindo todos os índices: 

```
String indexName = "unique_restaurantId_idx";
Document keys = new Document("cuisine", 1);
// Drop index by name
collection.dropIndex(indexName);
            
// Drop index by keys
collection.dropIndex(keys);
            
// Drop all indexes
collection.dropIndexes();
```

Ao descartar índices usando várias chaves, verifique se há um índice composto contendo todas as chaves especificadas e se a ordem das chaves está correta. O código de exemplo de criação de índice acima mostra uma chave composta sobre “culinária” e recursos. Se você tentar eliminar essa chave composta, mas a ordem não for a usada para a criação, ocorrerá um MongoCommnadException erro da seguinte forma:

```
Document keys = new Document("features", 1)
    .append("cuisine", 1);
try {
    // Drop index by keys
    collection.dropIndex(keys);
    System.out.println("Successfully dropped index with keys: " + keys.toJson());

} catch (MongoCommandException commErr) {
    System.out.println("Error dropping index: " + commErr.getErrorMessage());
    throw new RuntimeException("MongoCommandException was thrown while dropping index", commErr);
}
```

O seguinte erro é exibido:

```
Error dropping index: Cannot drop index: index not found.
Tests run: 3, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.819 sec <<< FAILURE!
com.amazon.docdb.guide.DocDBGuideTest.testindexGuide()  Time elapsed: 0.817 sec  <<< FAILURE!
org.opentest4j.AssertionFailedError: Unexpected exception thrown: java.lang.RuntimeException: MongoCommandException was thrown while dropping index
```

## Determinação da seleção do índice e fornecimento de dicas de índice
<a name="w2aac43b9b7c17c13"></a>

O trabalho com a funcionalidade de explicação no Amazon DocumentDB é fundamental para que você entenda a performance das consultas e o uso de índices. Ao executar uma consulta, é possível acrescentar o método `explain()` para obter informações detalhadas sobre o plano da consulta, incluindo quais índices, se houver, estão sendo usados. O resultado `explain()` fornece informações sobre os estágios de execução da consulta, o número de documentos examinados e o tempo gasto em cada estágio. Essas informações são inestimáveis para identificar se um determinado índice está sendo usado de forma eficaz ou se a consulta pode se beneficiar de uma estrutura de índices diferente.

O método `explain()` pode ser encadeado com o método `find()`. O método `explain()` pode usar uma enumeração [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/ExplainVerbosity.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/ExplainVerbosity.html) opcional que determina o nível de verbosidade retornado por `explain()`. No momento, há suporte somente aos enumeradores `EXECUTION_STATS` e `QUERY_PLANNER` no DocumentDB. O exemplo de código a seguir mostra como obter um planejador de consultas para uma consulta específica:

```
// Query we want to analyze
Document query = new Document()
    .append("cuisine", "Thai")
    .append("rating.average", new Document("$gte", 4.0));


Document allPlansExplain = collection.find(query).explain(ExplainVerbosity.QUERY_PLANNER);
System.out.println("All Plans Explain:\n" + allPlansExplain.toJson());
```

O documento JSON a seguir é retornado para o nível de verbosidade do planejador de consultas:

```
{
  "queryPlanner": {
    "plannerVersion": 1,
    "namespace": "ProgGuideData.Restaurants",
    "winningPlan": {
      "stage": "IXSCAN",
      "indexName": "cuisine_idx",
      "direction": "forward"
    }
  },
  "serverInfo": {
    "host": "guidecluster3",
    "port": 27017,
    "version": "5.0.0"
  },
  "ok": 1,
  "operationTime": {
    "$timestamp": {
      "t": 1739221668,
      "i": 1
    }
  }
}
```

Você tem várias opções para influenciar ou forçar o Amazon DocumentDB a usar um índice específico. Os métodos `hint()` e `hintString()` permitem que você substitua o comportamento padrão de seleção de índice do otimizador de consultas especificando explicitamente qual índice deve ser usado para uma consulta. Embora o otimizador de consultas do DocumentDB geralmente faça boas escolhas para a seleção de índices, há cenários em que forçar a aprovação de um índice específico por meio de `hint()` ou `hintString()` pode ser benéfico, como ao lidar com dados distorcidos ou ao testar a performance do índice.

O exemplo de código a seguir força o uso do índice composto “cuisine\$1features\$1idx” para a mesma consulta que foi executada no código acima:

```
// Query we want to analyze
Document query = new Document()
    .append("cuisine", "Thai")
    .append("rating.average", new Document("$gte", 4.0));

List < Document > queryDocs = new ArrayList < > ();
collection.find(query).hintString("cuisine_features_idx").forEach(doc - > queryDocs.add(doc));
```

# Programação orientada a eventos com Amazon DocumentDB e Java
<a name="event-driven-programming"></a>

A programação orientada a eventos no contexto do Amazon DocumentDB representa um poderoso padrão arquitetônico em que as alterações no banco de dados servem como os principais geradores de eventos que acionam a lógica e os processos comerciais subsequentes. Quando os registros são inseridos, atualizados ou excluídos em uma coleção do DocumentDB, essas alterações agem como eventos que iniciam automaticamente vários processos posteriores, notificações ou tarefas de sincronização de dados. Esse padrão é particularmente valioso em sistemas distribuídos modernos, nos quais várias aplicações ou serviços precisam reagir às mudanças de dados em tempo real. O principal mecanismo de implementação da programação orientada a eventos no DocumentDB é por meio de fluxos de alterações.

**nota**  
Este guia pressupõe que você tenha habilitado fluxos de alterações em uma coleção com a qual você esteja trabalhando. Consulte [Usar fluxos de alterações com o Amazon DocumentDB](change_streams.md) para saber como habilitar fluxos de alterações na coleção. 

**Trabalho com fluxos de alterações da aplicação em Java**

O método `watch()` no driver de Java do MongoDB é o principal mecanismo para monitorar alterações de dados em tempo real no Amazon DocumentDB. O método `watch()` pode ser chamado por objetos [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoClient.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoClient.html), [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoDatabase.html#watch(com.mongodb.client.ClientSession,java.lang.Class)](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoDatabase.html#watch(com.mongodb.client.ClientSession,java.lang.Class)) e [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoCollection.html#watch()](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoCollection.html#watch()).

O método `watch()` retorna uma instância de [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/ChangeStreamIterable.html#startAtOperationTime(org.bson.BsonTimestamp)](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/ChangeStreamIterable.html#startAtOperationTime(org.bson.BsonTimestamp)) que oferece suporte a várias opções de configuração, incluindo pesquisa completa de documentos para atualizações, fornecimento de tokens de retomada e registro de data e hora para fins de confiabilidade e estágios de agregação de pipeline para filtrar alterações. 

[https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/ChangeStreamIterable.html#startAtOperationTime(org.bson.BsonTimestamp)](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/ChangeStreamIterable.html#startAtOperationTime(org.bson.BsonTimestamp)) implementa a interface Java principal `Iterable` e pode ser usada com`forEach()`. Para capturar eventos usando `forEach()`, passe uma função de retorno de chamada para `forEach()` que processe o evento alterado. O trecho de código a seguir mostra como abrir um fluxo de alterações em uma coleção para iniciar o monitoramento de eventos de alteração:

```
ChangeStreamIterable < Document > iterator = collection.watch();
iterator.forEach(event - > {
    System.out.println("Received a change: " + event);
});
```

Outra forma de percorrer todos os eventos de mudança é abrir um cursor que mantenha uma conexão com o cluster e receba continuamente novos eventos de alteração à medida que eles ocorram. Para obter um cursor de fluxos de alterações, use o método `cursor()` do objeto [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/ChangeStreamIterable.html#startAtOperationTime(org.bson.BsonTimestamp)](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/ChangeStreamIterable.html#startAtOperationTime(org.bson.BsonTimestamp)). O exemplo de código a seguir mostra como monitorar eventos de alteração usando o cursor:

```
try (MongoChangeStreamCursor < ChangeStreamDocument < Document >> cursor = collection.watch().cursor()) {
    System.out.println(cursor.tryNext());
}
```

Como prática recomendada, crie o [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoChangeStreamCursor.html#getResumeToken()](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/MongoChangeStreamCursor.html#getResumeToken())em uma try-with-resource instrução ou feche manualmente o cursor. Chamar o método `cursor()` em [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/ChangeStreamIterable.html#startAtOperationTime(org.bson.BsonTimestamp)](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/ChangeStreamIterable.html#startAtOperationTime(org.bson.BsonTimestamp)) retornará um `MongoChangeStreamCursor` que é criado sobre um objeto [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/changestream/ChangeStreamDocument.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/changestream/ChangeStreamDocument.html). 

A classe [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/changestream/ChangeStreamDocument.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/changestream/ChangeStreamDocument.html) é um componente crucial que representa eventos de mudança individuais no fluxo. Ela contém informações detalhadas sobre cada modificação, incluindo o tipo de operação (inserir, atualizar, excluir, substituir), a chave do documento, as informações do namespace e o conteúdo completo do documento, quando disponível. A classe fornece métodos para acessar vários aspectos do evento de alteração, como `getOperationType()` para determinar o tipo de alteração, `getFullDocument()` para acessar o estado completo do documento e `getDocumentKey()` para identificar o documento modificado.

O objeto [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/changestream/ChangeStreamDocument.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/changestream/ChangeStreamDocument.html) fornece duas informações importantes, um token de retomada e a hora do evento de mudança.

Os tokens de retomada e as operações baseadas em tempo nos fluxos de alterações do DocumentDB fornecem mecanismos cruciais para manter a continuidade e gerenciar o acesso histórico aos dados. Um token de retomada é um identificador exclusivo gerado para cada evento de alteração, servindo como um marcador que permite que as aplicações reiniciem o processamento do fluxo de alterações a partir de um ponto específico após desconexões ou falhas. Quando um cursor de fluxo de alterações é criado, ele pode usar um token de retomada armazenado anteriormente por meio da opção `resumeAfter()`, permitindo que o fluxo continue de onde parou, em vez de começar do início ou perder eventos.

As operações baseadas em tempo nos fluxos de alterações oferecem diferentes abordagens para gerenciar o ponto de partida do monitoramento de eventos de mudança. A opção `startAtOperationTime()` permite que você comece a observar as alterações que ocorreram em ou após um carimbo de data e hora específico. Esses recursos baseados em tempo são particularmente valiosos em cenários que exigem processamento, point-in-time recuperação ou sincronização de dados históricos entre sistemas.

O exemplo de código a seguir recupera o evento associado ao documento inserido, captura seu token de retomada e, em seguida, fornece esse token para iniciar o monitoramento de eventos após o evento de inserção. O evento é associado ao evento de atualização e, em seguida, obtém a hora do cluster em que a atualização aconteceu e usa esse carimbo de data/hora como ponto de partida para processamento adicional.

```
BsonDocument resumeToken;
BsonTimestamp resumeTime;

try (MongoChangeStreamCursor < ChangeStreamDocument < Document >> cursor = collection.watch().cursor()) {
    System.out.println("****************** Insert Document *******************");
    ChangeStreamDocument < Document > insertChange = cursor.tryNext();
    resumeToken = insertChange.getResumeToken();
    printJson(cursor.tryNext());
}
try (MongoChangeStreamCursor < ChangeStreamDocument < Document >> cursor = collection.watch()
    .resumeAfter(resumeToken)
    .cursor()) {
    System.out.println("****************** Update Document *******************");
    ChangeStreamDocument < Document > insertChange = cursor.tryNext();
    resumeTime = insertChange.getClusterTime();
    printJson(cursor.tryNext());
}
try (MongoChangeStreamCursor < ChangeStreamDocument < Document >> cursor = collection.watch()
    .startAtOperationTime(resumeTime)
    .cursor()) {
    System.out.println("****************** Delete Document *******************");
    printJson(cursor.tryNext());
  }
```

Por padrão, o evento de atualização de alteração não inclui o documento completo, apenas as alterações que foram feitas. Se você precisar acessar o documento completo que foi atualizado, é possível chamar o método `fullDocument()` no objeto [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/ChangeStreamIterable.html#startAtOperationTime(org.bson.BsonTimestamp)](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-sync/com/mongodb/client/ChangeStreamIterable.html#startAtOperationTime(org.bson.BsonTimestamp)). Lembre-se de que, quando você solicita a devolução de um documento completo para um evento de atualização, ele retorna o documento que existe no momento em que a chamada para alterar fluxos é feita.

Esse método usa uma enumeração [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/changestream/FullDocument.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/changestream/FullDocument.html) como parâmetro. No momento, o Amazon DocumentDB só oferece suporte a DEFAULT e a valores `UPDATE_LOOKUP`. O trecho de código a seguir mostra como solicitar o documento completo para eventos de atualização ao começar a observar as alterações:

```
try (MongoChangeStreamCursor < ChangeStreamDocument < Document >> cursor = collection.watch().fullDocument(FullDocument.UPDATE_LOOKUP).cursor())
```

# Usando a validação do esquema JSON
<a name="json-schema-validation"></a>

Usando o operador de consulta de avaliação `$jsonSchema`, você pode validar documentos que estão sendo inseridos em suas coleções.

**Topics**
+ [Criação e uso da validação do esquema JSON](#get-started-with-validation)
+ [Palavras-chave com suporte](#json-supported-keywords)
+ [bypassDocumentValidation](#json-schema-bypass)
+ [Limitações](#json-schema-limitations)

## Criação e uso da validação do esquema JSON
<a name="get-started-with-validation"></a>

### Criação de uma coleção com validação de esquema
<a name="create-collection-with-validation"></a>

Você pode criar uma coleção com regras de operação e validação do `createCollection`. Essas regras de validação são aplicadas durante inserções ou atualizações de documentos do Amazon DocumentDB. O exemplo de código a seguir mostra as regras de validação para uma coleção de funcionários:

```
db.createCollection("employees", {
   "validator": {
      "$jsonSchema": {
         "bsonType": "object",
         "title": "employee validation",
         "required": [ "name", "employeeId"],
         "properties": {
            "name": {
                  "bsonType": "object",
                  "properties": {
                     "firstName": {
                        "bsonType": ["string"]
                     },
                     "lastName": {
                        "bsonType": ["string"]
                     }
                  },
                  "additionalProperties" : false 
            },
            "employeeId": {
               "bsonType": "string",
               "description": "Unique Identifier for employee"
            },
             "salary": {
               "bsonType": "double"
            },
            "age": {
               "bsonType": "number"
            }
         },
         "additionalProperties" : true 
      }
   },
   "validationLevel": "strict", "validationAction": "error"
} )
```

### Inserindo um documento válido
<a name="insert-valid-document"></a>

O exemplo a seguir insere documentos que estão em conformidade com as regras de validação de esquema acima:

```
db.employees.insert({"name" : { "firstName" : "Carol" , "lastName" : "Smith"}, "employeeId": "c720a" , "salary": 1000.0 })
db.employees.insert({ "name" : { "firstName" : "William", "lastName" : "Taylor" }, "employeeId" : "c721a", "age" : 24})
```

### Inserindo um documento inválido
<a name="insert-invalid-document"></a>

O exemplo a seguir insere documentos que não estão em conformidade com as regras de validação de esquema acima. Neste exemplo, o valor do EmployeeID não é uma string:

```
db.employees.insert({
    "name" : { "firstName" : "Carol" , "lastName" : "Smith"}, 
    "employeeId": 720 , 
    "salary": 1000.0 
})
```

Este exemplo mostra a sintaxe incorreta no documento.

### Modifica uma coleção.
<a name="modify-collection"></a>

O comando `collMod` é usado para adicionar ou modificar as regras de validação da coleção existente. O exemplo a seguir adiciona um campo de salário à lista de campos obrigatórios:

```
db.runCommand({"collMod" : "employees", 
   "validator": {
      "$jsonSchema": {
         "bsonType": "object",
         "title": "employee validation",
         "required": [ "name", "employeeId", "salary"],
         "properties": {
            "name": {
                  "bsonType": "object",
                  "properties": {
                     "firstName": {
                        "bsonType": ["string"]
                     },
                     "lastName": {
                        "bsonType": ["string"]
                     }
                  },
                  "additionalProperties" : false 
            },
            "employeeId": {
               "bsonType": "string",
               "description": "Unique Identifier for employee"
            },
             "salary": {
               "bsonType": "double"
            },
            "age": {
               "bsonType": "number"
            }
         },
         "additionalProperties" : true 
      }
   }
} )
```

### Documentos de endereçamento adicionados antes da alteração das regras de validação
<a name="pre-validation-docs"></a>

Para endereçar documentos que foram adicionados à sua coleção antes da alteração das regras de validação, use os seguintes modificadores `validationLevel`:
+ **estrito**: aplica regras de validação em todas as inserções e atualizações.
+ **moderado**: aplica regras de validação a documentos válidos existentes. Durante as atualizações, os documentos inválidos existentes não são verificados.

No exemplo a seguir, depois de atualizar as regras de validação na coleção chamada “funcionários”, o campo salário é obrigatório. A atualização do seguinte documento falhará:

```
db.runCommand({ 
    update: "employees", 
    updates: [{ 
        q: { "employeeId": "c721a" }, 
        u: { age: 25 , salary : 1000}, 
        upsert: true }] 
})
```

O Amazon DocumentDB retorna a seguinte saída:

```
{
"n" : 0,
    "nModified" : 0,
    "writeErrors" : [
        {
"index" : 0,
            "code" : 121,
            "errmsg" : "Document failed validation"
        }
    ],
    "ok" : 1,
    "operationTime" : Timestamp(1234567890, 1)
}
```

Atualizar o nível de validação para `moderate` permitirá que o documento acima seja atualizado com sucesso:

```
db.runCommand({
    "collMod" : "employees", 
    validationLevel : "moderate"
})

db.runCommand({ 
    update: "employees", 
    updates: [{ 
        q: { "employeeId": "c721a" }, 
        u: { age: 25 , salary : 1000}, 
        upsert: true }]
})
```

O Amazon DocumentDB retorna a seguinte saída:

```
{
"n" : 1,
    "nModified" : 1,
    "ok" : 1,
    "operationTime" : Timestamp(1234567890, 1)
}
```

### Recuperando documentos com o \$1jsonSchema
<a name="json-retrieve-docs"></a>

O operador `$jsonSchema` pode ser usado como filtro para consultar documentos que correspondam ao esquema JSON. Esse é um operador de nível superior que pode estar presente em documentos de filtro como um campo de nível superior ou usado com operadores de consulta, como `$and`, `$or` e `$nor`. Os exemplos a seguir mostram o uso de \$1jsonSchema como um filtro individual e com outros operadores de filtro:

Documento inserido em uma coleção de “funcionários”:

```
{ "name" : { "firstName" : "Carol", "lastName" : "Smith" }, "employeeId" : "c720a", "salary" : 1000 }
{ "name" : { "firstName" : "Emily", "lastName" : "Brown" }, "employeeId" : "c720b", "age" : 25, "salary" : 1050.2 }
{ "name" : { "firstName" : "William", "lastName" : "Taylor" }, "employeeId" : "c721a", "age" : 24, "salary" : 1400.5 }
{ "name" : { "firstName" : "Jane", "lastName" : "Doe" }, "employeeId" : "c721a", "salary" : 1300 }
```

Coleção filtrada somente com o operador `$jsonSchema`:

```
db.employees.find({ 
       $jsonSchema: { required: ["age"] } })
```

O Amazon DocumentDB retorna a seguinte saída:

```
{ "_id" : ObjectId("64e5f91c6218c620cf0e8f8b"), "name" : { "firstName" : "Emily", "lastName" : "Brown" }, "employeeId" : "c720b", "age" : 25, "salary" : 1050.2 }
{ "_id" : ObjectId("64e5f94e6218c620cf0e8f8c"), "name" : { "firstName" : "William", "lastName" : "Taylor" }, "employeeId" : "c721a", "age" : 24, "salary" : 1400.5 }
```

Coleção filtrada com o operador `$jsonSchema` e outro operador:

```
db.employees.find({ 
       $or: [{ $jsonSchema: { required: ["age", "name"]}}, 
            { salary: { $lte:1000}}]});
```

O Amazon DocumentDB retorna a seguinte saída:

```
{ "_id" : ObjectId("64e5f8886218c620cf0e8f8a"), "name" : { "firstName" : "Carol", "lastName" : "Smith" }, "employeeId" : "c720a", "salary" : 1000 }
{ "_id" : ObjectId("64e5f91c6218c620cf0e8f8b"), "name" : { "firstName" : "Emily", "lastName" : "Brown" }, "employeeId" : "c720b", "age" : 25, "salary" : 1050.2 }
{ "_id" : ObjectId("64e5f94e6218c620cf0e8f8c"), "name" : { "firstName" : "William", "lastName" : "Taylor" }, "employeeId" : "c721a", "age" : 24, "salary" : 1400.5 }
```

Coleção filtrada com o operador `$jsonSchema` e com o `$match` no filtro agregado:

```
db.employees.aggregate(
    [{ $match: { 
        $jsonSchema: { 
            required: ["name", "employeeId"],  
            properties: {"salary" :{"bsonType": "double"}}
        }
       }
    }]
)
```

O Amazon DocumentDB retorna a seguinte saída:

```
{ 
"_id" : ObjectId("64e5f8886218c620cf0e8f8a"),
 "name" : { "firstName" : "Carol", "lastName" : "Smith" },
"employeeId" : "c720a",
"salary" : 1000 
}
{
"_id" : ObjectId("64e5f91c6218c620cf0e8f8b"),
"name" : { "firstName" : "Emily", "lastName" : "Brown" },
"employeeId" : "c720b",
"age" : 25,
"salary" : 1050.2
}
{
"_id" : ObjectId("64e5f94e6218c620cf0e8f8c"),
"name" : { "firstName" : "William", "lastName" : "Taylor" },
"employeeId" : "c721a",
"age" : 24,
"salary" : 1400.5
}
{
"_id" : ObjectId("64e5f9786218c620cf0e8f8d"),
"name" : { "firstName" : "Jane", "lastName" : "Doe" },
"employeeId" : "c721a",
"salary" : 1300
}
```

### Visualizando as regras de validação existentes
<a name="view-validation-rules"></a>

Para ver as regras de validação existentes em uma coleção, use:

```
db.runCommand({
    listCollections: 1, 
    filter: { name: 'employees' }
})
```

O Amazon DocumentDB retorna a seguinte saída:

```
{
    "waitedMS" : NumberLong(0),
    "cursor" : {
        "firstBatch" : [
            {
                "name" : "employees",
                "type" : "collection",
                "options" : {
                    "autoIndexId" : true,
                    "capped" : false,
                    "validator" : {
                        "$jsonSchema" : {
                            "bsonType" : "object",
                            "title" : "employee validation",
                            "required" : [
                                "name",
                                "employeeId",
                                "salary"
                            ],
                            "properties" : {
                                "name" : {
                                    "bsonType" : "object",
                                    "properties" : {
                                        "firstName" : {
                                            "bsonType" : [
                                                "string"
                                            ]
                                        },
                                        "lastName" : {
                                            "bsonType" : [
                                                "string"
                                            ]
                                        }
                                    },
                                    "additionalProperties" : false
                                },
                                "employeeId" : {
                                    "bsonType" : "string",
                                    "description" : "Unique Identifier for employee"
                                },
                                "salary" : {
                                    "bsonType" : "double"
                                },
                                "age" : {
                                    "bsonType" : "number"
                                }
                            },
                            "additionalProperties" : true
                        }
                    },
                    "validationLevel" : "moderate",
                    "validationAction" : "error"
                },
                "info" : {
                    "readOnly" : false
                },
                "idIndex" : {
                    "v" : 2,
                    "key" : {
                        "_id" : 1
                    },
                    "name" : "_id_",
                    "ns" : "test.employees"
                }
            }
        ],
        "id" : NumberLong(0),
        "ns" : "test.$cmd.listCollections"
    },
    "ok" : 1,
    "operationTime" : Timestamp(1692788937, 1)
}
```

O Amazon DocumentDB também mantém as regras de validação no estágio de agregação de `$out`.

## Palavras-chave com suporte
<a name="json-supported-keywords"></a>

Os seguintes campos são compatíveis com os comandos `create` e `collMod`:
+ **`Validator`** — Oferece suporte ao operador `$jsonSchem`.
+ **`ValidationLevel`** — Oferece suporte aos valores `off`, `strict` e `moderate`.
+ **`ValidationAction`** — Oferece suporte ao valor `error`.

O operador \$1jsonSchema é compatível com as seguintes palavras-chave:
+ `additionalItems`
+ `additionalProperties`
+ `allOf`
+ `anyOf`
+ `bsonType`
+ `dependencies`
+ `description`
+ `enum`
+ `exclusiveMaximum`
+ `exclusiveMinimum`
+ `items`
+ `maximum`
+ `minimum`
+ `maxItems`
+ `minItems`
+ `maxLength`
+ `minLength`
+ `maxProperties`
+ `minProperties`
+ `multipleOf`
+ `not`
+ `oneOf`
+ `pattern`
+ `patternProperties`
+ `properties`
+ `required`
+ `title`
+ `type`
+ `uniqueItems`

## bypassDocumentValidation
<a name="json-schema-bypass"></a>

O Amazon DocumentDB oferece suporte a `bypassDocumentValidation` para os seguintes comandos e métodos:
+ `insert`
+ `update`
+ `findAndModify`
+ Estágio `$out` no comando `aggregate` e no método `db.collection.aggregate()`

O Amazon DocumentDB não oferece suporte aos seguintes comandos para `bypassDocumentValidation`: 
+ `$merge` no comando `aggregate` e no método `db.collection.aggregate()`
+ Comando `mapReduce` e método `db.collection.mapReduce()`
+ Comando `applyOps`

## Limitações
<a name="json-schema-limitations"></a>

As limitações a seguir se aplicam à validação `$jsonSchema`:
+ O Amazon DocumentDB retorna o erro “Falha na validação do documento” quando uma operação falha na regra de validação.
+ Os clusters elásticos do Amazon DocumentDB não suportam `$jsonSchema`.