

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Realización de operaciones CRUD en Amazon DocumentDB con Java
<a name="java-crud-operations"></a>

En esta sección se describe cómo realizar las operaciones CRUD (crear, leer, actualizar, eliminar) en Amazon DocumentDB con los controladores Java de MongoDB.

**Topics**
+ [Creación e inserción de documentos en una colección de DocumentDB](#creating-inserting)
+ [Lectura y recuperación de datos de una colección de DocumentDB](#reading-retrieving)
+ [Actualización de documentos existentes en una colección de DocumentDB](#updating-documents)
+ [Eliminación de documentos de una colección de DocumentDB](#deleting-documents)
+ [Gestión de errores con lógica de reintento](#error-handling)

## Creación e inserción de documentos en una colección de DocumentDB
<a name="creating-inserting"></a>

La inserción de documentos en Amazon DocumentDB le permite añadir nuevos datos a sus colecciones. Existen varias formas de realizar las inserciones, en función de sus necesidades y del volumen de datos con el que esté trabajando. El método más básico para insertar un documento individual en la colección es `insertOne()`. Para insertar varios documentos a la vez, puede utilizar el método de `insertMany()`, que le permite añadir una serie de documentos en una sola operación. Otro método para insertar muchos documentos en una colección de DocumentDB es `bulkWrite()`. En esta guía, analizamos todos estos métodos para crear documentos en una colección de DocumentDB.

**`insertOne()`**

Empecemos por examinar cómo insertar un documento individual en una colección de Amazon DocumentDB. La inserción de un único documento se realiza mediante el método `insertOne()`. Este método toma un objeto [BsonDocument](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/bson/org/bson/BsonDocument.html)para insertarlo y devuelve un [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 se puede utilizar para obtener el identificador de objeto del nuevo documento insertado. El siguiente código de ejemplo muestra la inserción de un documento de restaurante en la colección:

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

Cuando use `insertOne()`, asegúrese de incluir una gestión de errores adecuada. Por ejemplo, en el código anterior, «`restaurantId`» tiene un índice único y, por lo tanto, cuando vuelva a ejecutar este código, se generará la siguiente `MongoWriteException`:

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

Los métodos principales utilizados para insertar muchos documentos en una colección son insertMany() y `bulkWrite()`. 

El método `insertMany()` es la forma más sencilla de insertar varios documentos en una sola operación. Acepta una lista de documentos y los inserta en la colección. Este método es ideal cuando se inserta un lote de documentos nuevos que son independientes entre sí y no requieren ningún procesamiento especial ni operaciones mixtas. El siguiente código muestra la lectura de documentos JSON de un archivo y su inserción en la colección. La `insertMany()` función devuelve un [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 se puede utilizar para obtener todos IDs los documentos insertados.

```
// 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)**

El método `bulkWrite()` permite realizar múltiples operaciones de escritura (insertar, actualizar, eliminar) en un solo lote. Puede usar `bulkWrite()` cuando necesite realizar diferentes tipos de operaciones en un solo lote, como insertar algunos documentos y actualizar otros. `bulkWrite()` admite dos tipos de escritura por lotes, ordenada y desordenada:
+ *Operaciones ordenadas* (predeterminado): Amazon DocumentDB procesa las operaciones de escritura de forma secuencial y se detiene ante el primer error que detecta. Esto resulta útil cuando el orden de las operaciones es importante, por ejemplo, cuando las operaciones posteriores dependen de las anteriores. Sin embargo, las operaciones ordenadas suelen ser más lentas que las desordenadas. En el caso de las operaciones ordenadas, debe abordar el caso de que el lote se detenga ante el primer error, lo que podría dejar algunas operaciones sin procesar.
+ *Operaciones desordenadas*: permite a Amazon DocumentDB procesar las inserciones como una sola ejecución en la base de datos. Si se produce un error en un documento, la operación continúa con el resto de los documentos. Esto resulta especialmente útil cuando se insertan grandes cantidades de datos y se pueden tolerar algunos errores, como durante la migración de datos o las importaciones masivas, donde algunos documentos pueden fallar debido a la duplicación de claves. En el caso de operaciones desordenadas, debe abordar las situaciones de éxito parcial, en los que algunas operaciones se realizan correctamente y otras no.

Al trabajar con el método `bulkWrite()`, se requieren algunas clases esenciales. En primer lugar, la clase [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) sirve como clase base para todas las operaciones de escritura y tiene implementaciones 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) y [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), que manejan diferentes tipos de operaciones.

La [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)clase es necesaria para configurar el comportamiento de las operaciones masivas, como configurar la ordered/unordered ejecución o omitir la validación de los documentos. La clase [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) proporciona información detallada sobre los resultados de la ejecución, incluidos los recuentos de documentos insertados, actualizados y eliminados.

Para la gestión de errores, la clase [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) es fundamental, ya que contiene información sobre los posibles errores que se produzcan durante la operación masiva, mientras que la clase [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) proporciona detalles específicos sobre los errores de las operaciones individuales. El siguiente código muestra un ejemplo de inserción de una lista de documentos, así como de actualización y eliminación de un solo documento, todo ello mediante la ejecución de una llamada a un único método `bulkWrite()`. El código también muestra cómo trabajar con [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) y [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), así como la correcta gestión de errores de la operación de `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());
}
```

**Escrituras reintentables**

A diferencia de MongoDB, Amazon DocumentDB no admite el reintento de las escrituras. En consecuencia, debe implementar una lógica de reintento personalizada en sus aplicaciones, especialmente para solucionar problemas de red o la falta temporal de disponibilidad del servicio. Por lo general, una estrategia de reintentos bien implementada implica aumentar la demora entre los reintentos y limitar el número total de reintentos. Consulte [Gestión de errores con lógica de reintento](#error-handling) a continuación para conocer un ejemplo de código sobre cómo crear una lógica de reintentos con gestión de errores.

## Lectura y recuperación de datos de una colección de DocumentDB
<a name="reading-retrieving"></a>

La consulta de documentos en Amazon DocumentDB gira en torno a varios componentes clave que permiten recuperar y manipular datos con precisión. El [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 es la consulta fundamental APIs en los controladores Java de MongoDB. Permite la recuperación de datos complejos con numerosas opciones para filtrar, ordenar y proyectar resultados. Además del 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) y [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) son otros dos componentes fundamentales que proporcionan los componentes básicos para las operaciones de consulta en los controladores Java de MongoDB.

La clase `Filters` es una clase de utilidad del controlador Java de MongoDB que proporciona una API fluida para generar un constructo de filtros de consultas. Esta clase ofrece métodos de fábrica estáticos que crean instancias de objetos `Bson` que representan diversas condiciones de consulta. Los métodos más comúnmente utilizados son `eq()` para las comparaciones de igualdad, `gt()`, `lt()`, `gte()` y `lte()` para las comparaciones numéricas, `and()` y `or()` para las combinaciones de condiciones múltiples, `in()` y `nin()` para las pruebas de suscripción a matrices y `regex()` para la coincidencia de patrones. La clase está diseñada para ser segura en relación con los tipos y proporciona una mejor comprobación en tiempo de compilación en comparación con las consultas basadas en documentos sin procesar, lo que la convierte en el enfoque preferido para crear consultas de DocumentDB en aplicaciones Java. La gestión de errores es sólida, con claras excepciones en el caso de constructos de filtros no válidas.

`FindIterable` es una interfaz especializada diseñada para gestionar el resultado del método `find()`. Proporciona un amplio conjunto de métodos para refinar y controlar la ejecución de consultas, y ofrece una API fluida para el encadenamiento de métodos. La interfaz incluye métodos esenciales de modificación de consultas, como `limit()` para restringir el número de documentos devueltos, `skip()` para paginar, `sort()` para ordenar los resultados, `projection()` para seleccionar campos específicos y `hint()` para seleccionar índices. Las operaciones de agrupar en lotes, omitir y limitar en `FindIterable` son herramientas esenciales de paginación y administración de datos que ayudan a controlar la forma en que se recuperan y procesan los documentos de la base de datos.

Agrupar en lotes (`batchSize`) controla el número de documentos que DocumentDB devuelve al cliente en una única red de ida y vuelta. Cuando establece un tamaño de lote, DocumentDB no devuelve todos los documentos coincidentes a la vez, sino que los devuelve en grupos del tamaño de lote especificado. 

Omitir le permite desplazar el punto de partida de los resultados y, básicamente, le indica a DocumentDB que omita un número específico de documentos antes de empezar a devolver las coincidencias. Por ejemplo, `skip(20)` omitirá los primeros 20 documentos coincidentes. Esto se suele utilizar en situaciones de paginación en los que se desean recuperar páginas de resultados posteriores. 

Limitar restringe el número total de documentos que se pueden devolver a partir de una consulta. Si especifica `limit(n)`, DocumentDB dejará de devolver documentos después de haber devuelto «n» documentos, incluso si hay más coincidencias en la base de datos. 

`FindIterable` admite patrones de iterador y cursor cuando recupera documentos de Amazon DocumentDB. La ventaja de usar `FindIterable` como iterador es que permite la carga diferida de los documentos y solo los recupera cuando la aplicación los solicita. Otra ventaja de usar el iterador es que no es responsable de mantener la conexión con el clúster y, por lo tanto, no es necesario cerrar la conexión de forma explícita. 

`FindIterable` también proporciona soporte para [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 utilizar patrones de cursor cuando trabaja con consultas de Amazon DocumentDB. El `MongoCursor` es una implementación específica del controlador Java de MongoDB que proporciona control sobre las operaciones de la base de datos y la administración de recursos. Implementa la `AutoCloseable` interfaz, lo que permite una gestión explícita de los recursos mediante try-with-resources bloques, lo cual es crucial para cerrar correctamente las conexiones de las bases de datos y liberar los recursos del servidor. De forma predeterminada, el tiempo de espera del cursor es de 10 minutos y DocumentDB no le da la opción de cambiar este comportamiento de tiempo de espera. Cuando trabaje con datos agrupados, asegúrese de recuperar el siguiente lote de datos antes de que se agote el tiempo de espera del cursor. Una consideración clave a la hora de usar el `MongoCursor` es que requiere un cierre explícito para evitar la pérdida de recursos.

En esta sección, se presentan varios ejemplos de `find()`, `Filters` y `FindIterable`.

En el siguiente ejemplo de código se muestra cómo usar `find()` para recuperar un solo documento con su campo «restaurantId»:

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

Si bien el uso de `Filters` permite comprobar mejor los errores en el momento de la compilación, el controlador java también permite especificar un filtro de `Bson` directamente en el método `find()`. El siguiente código de ejemplo pasa el documento `Bson` a `find()`:

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

El siguiente código de ejemplo muestra varios ejemplos del uso de la clase `Filters` con `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));
```

En el siguiente ejemplo se muestra cómo encadenar las operaciones de `sort()`, `skip()`, `limit()` y `batchSize()` en un objeto de `FindIterable`. El orden en que se proporcionen estas operaciones influirá en el rendimiento de la consulta. Como práctica recomendada, el orden de estas operaciones debe ser `sort()`, `projection()`, `skip()`, `limit()` y `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);
```

El siguiente ejemplo de código muestra cómo crear un iterador en `FindIterable`. Usa el constructo `forEach` de Java para recorrer el conjunto de resultados.

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

En el último ejemplo de código de `find()`, se muestra cómo usar el `cursor()` para la recuperación de documentos. Crea el cursor en el bloque de prueba, lo que garantiza que el cursor se cierre cuando el código salga del bloque de prueba.

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

## Actualización de documentos existentes en una colección de DocumentDB
<a name="updating-documents"></a>

Amazon DocumentDB proporciona mecanismos flexibles y potentes para modificar los documentos existentes e insertar otros nuevos cuando no existen. El controlador Java de MongoDB ofrece varios métodos de actualización: `updateOne()` para actualizaciones de un solo documento, `updateMany()` para actualizaciones de varios documentos y `replaceOne()` para la sustitución completa de documentos. Además de estos tres 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) y [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) son otros componentes fundamentales que proporcionan los componentes básicos para las operaciones de actualización en los controladores Java de MongoDB. 

La clase `Updates` del controlador Java de MongoDB es una clase de utilidad que proporciona métodos de fábrica estáticos para crear operadores de actualización. Sirve como el compilador principal para crear operaciones de actualización de forma legible y segura. Métodos básicos como `set()`, `unset()` y `inc()` permiten la modificación directa de los documentos. El poder de esta clase se hace evidente cuando se combinan varias operaciones mediante el método `Updates.combine()`, que permite ejecutar varias operaciones de actualización de forma atómica, lo que garantiza la coherencia de datos.

`UpdateOptions` es una potente clase de configuración del controlador Java de MongoDB que proporciona capacidades de personalización esenciales para las operaciones de actualización de documentos. Dos aspectos importantes de esta clase son la compatibilidad con actualizaciones y filtros de matriz para las operaciones de actualización. La característica de actualización, habilitada mediante `upsert(true)`, permite crear nuevos documentos cuando no se encuentra ningún documento coincidente durante una operación de actualización. Mediante `arrayFilters()`, la operación de actualización puede actualizar con precisión los elementos de la matriz que cumplan criterios específicos.

`UpdateResult` en el controlador Java de MongoDB proporciona el mecanismo de retroalimentación que detalla el resultado de una operación de actualización. Esta clase agrupa tres métricas clave: el número de documentos que cumplen los criterios de actualización (`matchedCount`), el número de documentos realmente modificados (`modifiedCount`) y la información sobre cualquier documento alterado (`upsertedId`). Comprender estas métricas es esencial para gestionar correctamente los errores, verificar las operaciones de actualización y mantener la coherencia de datos en las aplicaciones.

### Actualización y sustitución de un solo documento
<a name="update-single-doc"></a>

En DocumentDB, la actualización de un solo documento se puede realizar mediante el método updateOne(). Este método utiliza un parámetro de filtro, normalmente proporcionado por la clase `Filters`, para identificar el documento que se va a actualizar, un parámetro de `Updat` que determina qué campos se van a actualizar y un parámetro de `UpdateOptions` opcional para establecer diferentes opciones de actualización. El uso del método `updateOne()` solo actualizará el primer documento que coincida con los criterios de selección. El siguiente código de ejemplo actualiza un solo campo de un documento:

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

Para actualizar varios campos de un documento, use `updateOne()` con `Update.combine()` como se muestra en el siguiente ejemplo. En este ejemplo también se muestra cómo agregar un elemento a una matriz del 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);
```

En el siguiente ejemplo de código se muestra cómo actualizar un documento de la base de datos. Si el documento especificado no existe, la operación lo insertará automáticamente como documento nuevo. Este código también muestra cómo utilizar las métricas disponibles a través del objeto de `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)");
}
```

El siguiente ejemplo de código muestra cómo reemplazar completamente un documento existente por uno nuevo mediante el método `replaceOne()`, en lugar de actualizar campos individuales. El método `replaceOne()` sobrescribe todo el documento y conserva únicamente el campo `_id` del original. Si varios documentos coinciden con los criterios del filtro, solo se reemplaza el primer documento encontrado.

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

### Actualización de documentos múltiples
<a name="update-multiple-docs"></a>

Hay dos formas de actualizar varios documentos de una colección de forma simultánea. Puede utilizar el método de `updateMany()` o usar el [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) con el método `bulkWrite()`. El método `updateMany()` utiliza un parámetro de filtro para seleccionar los documentos que se van a actualizar, el parámetro `Update` para identificar los campos que se van a actualizar y un parámetro `UpdateOptions` opcional para especificar las opciones de actualización.

El siguiente ejemplo de código demuestra el uso del 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", "$$$"));
```

El siguiente ejemplo de código demuestra el método de `bulkWrite()` con la misma actualización:

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

## Eliminación de documentos de una colección de DocumentDB
<a name="deleting-documents"></a>

El controlador Java de MongoDB ofrece `deleteOne()` para eliminar un solo documento y `deleteMany()` para eliminar varios documentos que coincidan con criterios específicos. Al igual que la actualización, la operación de eliminación también se puede utilizar con el método `bulkWrite()`. Ambos `deleteOne()` y `deleteMany()` devuelven un 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 proporciona información sobre el resultado de la operación, incluido el recuento de documentos eliminados. A continuación, se muestra un ejemplo de cómo usar `deleteMany()` para eliminar varios 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());
```

## Gestión de errores con lógica de reintento
<a name="error-handling"></a>

Una estrategia sólida de gestión de errores con Amazon DocumentDB debería incluir la categorización de los errores en reintentables (como tiempos de espera de la red o problemas de conexión) y no reintentables (como errores de autenticación o consultas no válidas). En el caso de los errores de operación debidos a errores que deben reintentarse, se debe implementar un intervalo de tiempo entre cada reintento, así como un máximo de reintentos. Las operaciones CRUD deben realizarse en un bloque 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) y sus subclases. Además, debe incluir la supervisión y el registro de los errores para garantizar la visibilidad operativa. El siguiente es un ejemplo de código que muestra cómo implementar la gestión de errores de reintentos:

```
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);
    }
}
```