

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# Java を使用した Amazon DocumentDB での CRUD オペレーションの実行
<a name="java-crud-operations"></a>

このセクションでは、MongoDB Java ドライバーを使用して Amazon DocumentDB で CRUD (作成、読み取り、更新、削除) オペレーションを実行する方法について説明します。

**Topics**
+ [DocumentDB コレクションでのドキュメントの作成と挿入](#creating-inserting)
+ [DocumentDB コレクションからのデータの読み取りと取得](#reading-retrieving)
+ [DocumentDB コレクション内の既存のドキュメントの更新](#updating-documents)
+ [DocumentDB コレクションからのドキュメントの削除](#deleting-documents)
+ [再試行ロジックによるエラー処理](#error-handling)

## DocumentDB コレクションでのドキュメントの作成と挿入
<a name="creating-inserting"></a>

Amazon DocumentDB にドキュメントを挿入すると、コレクションに新しいデータを追加できるようになります。挿入を実行するには、ニーズと使用しているデータの量に応じて、いくつかの方法があります。個々のドキュメントをコレクションに挿入するための最も基本的なメソッドは `insertOne()` です。一度に複数のドキュメントを挿入するには、`insertMany()` メソッドを使用できます。これにより、ドキュメントの配列を 1 回のオペレーションで追加できます。DocumentDB コレクションに多くのドキュメントを挿入するもう 1 つのメソッドは `bulkWrite()` です。このガイドでは、DocumentDB コレクションでドキュメントを作成するためのこれらのすべてのメソッドについて説明します。

**`insertOne()`**

まず、個々のドキュメントを Amazon DocumentDB コレクションに挿入する方法を見てみましょう。単一のドキュメントを挿入するには、`insertOne()` メソッドを使用します。このメソッドは、挿入のために [BsonDocument](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/bson/org/bson/BsonDocument.html) を取得し、新しい挿入されたドキュメントのオブジェクト ID を取得するために使用できる [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) オブジェクトを返します。以下のコード例は、コレクションに 1 つのレストランドキュメントを挿入する方法を示しています。

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

`insertOne()` を使用する場合は、適切なエラー処理を必ず含めてください。例えば、上記のコードでは、「`restaurantId`」には一意のインデックスがあるため、このコードを再度実行すると、次の `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()**

コレクションに多くのドキュメントを挿入する主なメソッドは insertMany() と `bulkWrite()` です。

`insertMany()` メソッドは、1 回のオペレーションで複数のドキュメントを挿入する最も簡単な方法です。ドキュメントのリストを受け入れ、コレクションに挿入します。このメソッドは、互いに独立しており、特別な処理や混合オペレーションを必要としない新しいドキュメントのバッチを挿入する場合に最適です。次のコードは、ファイルから JSON ドキュメントを読み取ってコレクションに挿入する方法を示しています。`insertMany()` 関数は、挿入されたすべてのドキュメントの ID を取得するために使用できる [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` オブジェクトを返します。

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

`bulkWrite()` メソッドを使用すると、複数の書き込みオペレーション (挿入、更新、削除) を 1 つのバッチで実行できます。`bulkWrite()` は、一部のドキュメントを挿入して他のドキュメントを更新するなど、1 つのバッチでさまざまなタイプのオペレーションを実行する必要がある場合に使用できます。`bulkWrite()` は、順序付きと順序なしの 2 種類のバッチ書き込みをサポートしています。
+ *順序付けられたオペレーション* — (デフォルト) Amazon DocumentDB は書き込みオペレーションを順番に処理し、最初に発生したエラーで停止します。これは、後のオペレーションが以前のオペレーションに依存する場合など、オペレーションの順序が重要な場合に役立ちます。ただし、順序付けられたオペレーションは、通常、順序付けられていないオペレーションよりも遅くなります。順序付けられたオペレーションでは、バッチが最初のエラーで停止し、一部のオペレーションが未処理のままになる可能性があるケースに対処する必要があります。
+ *順序付けされていないオペレーション* — Amazon DocumentDB が挿入をデータベース内の 1 回の実行として処理できるようにします。1 つのドキュメントでエラーが発生した場合、オペレーションは残りのドキュメントで続行されます。これは、大量のデータを挿入していて、キーの重複が原因で一部のドキュメントが失敗する可能性のあるデータ移行や一括インポートなど、一部の障害を許容できる場合に特に便利です。順序付けされていないオペレーションでは、一部のオペレーションが成功し、他のオペレーションが失敗する部分的な成功シナリオに対処する必要があります。

`bulkWrite()` メソッドを使用する場合、必須のクラスがいくつかあります。まず、[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) クラスはすべての書き込みオペレーションのベースクラスとして機能し、[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)、[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) などの特定の実装で、さまざまなタイプのオペレーションを処理します。

[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) クラスは、順序付き/順序なしの実行の設定やドキュメントの検証のバイパスなど、一括オペレーションの動作を設定するために必要です。[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) クラスは、挿入、更新、および削除されたドキュメントの数など、実行結果に関する詳細情報を提供します。

エラー処理では、[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) クラスには一括オペレーション中の障害に関する情報が含まれているため、 クラスは重要です。一方、[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) クラスは個々のオペレーションの障害に関する特定の詳細を提供します。次のコードは、1 つの `bulkWrite()` メソッド呼び出しの実行中に、ドキュメントのリストを挿入し、1 つのドキュメントを更新および削除する例を示しています。このコードは、[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) および [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) の操作方法と、`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());
}
```

**再試行可能な書き込み**

MongoDB とは異なり、Amazon DocumentDB は再試行可能な書き込みをサポートしていません。そのため、特にネットワークの問題や一時的なサービス利用不能を処理するために、アプリケーションにカスタム再試行ロジックを実装する必要があります。適切に実装された再試行戦略では、通常、再試行間の遅延を増やし、再試行の合計数を制限します。エラー処理を使用して再試行ロジックを構築するコードサンプルについては、以下の [再試行ロジックによるエラー処理](#error-handling) を参照してください。

## DocumentDB コレクションからのデータの読み取りと取得
<a name="reading-retrieving"></a>

Amazon DocumentDB でのドキュメントのクエリは、データを正確に取得して操作できるいくつかの主要なコンポーネントを中心に展開されます。[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()) メソッドは、MongoDB Java ドライバーの基本的なクエリ API です。これにより、フィルタリング、ソート、結果の射影のための多数のオプションを使用して、複雑なデータ取得が可能になります。`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) と [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) は、MongoDB Java ドライバーでのクエリオペレーションの構成要素を提供する他の 2 つの基本的なコンポーネントです。

`Filters` クラスは、クエリフィルターを構築するための流暢な API を提供する MongoDB Java ドライバーのユーティリティクラスです。このクラスは、さまざまなクエリ条件を表す `Bson` オブジェクトのインスタンスを作成する静的ファクトリメソッドを提供します。最も一般的に使用されるメソッドには、等価比較では `eq()`、数値比較では `gt()`、`lt()`、`gte()`、`lte()`、複数の条件の組み合わせでは `and()`、`or()`、配列メンバーシップテストでは `in()`、`nin()`、パターンマッチングでは `regex()` が含まれます。クラスは、タイプセーフであるように設計されており、raw ドキュメントベースのクエリと比較してコンパイル時のチェックに優れているため、Java アプリケーションで DocumentDB クエリを構築するための推奨アプローチです。エラー処理は堅牢で、無効なフィルター構造には明確な例外がスローされます。

`FindIterable` は、 `find()` メソッドの結果を処理するように設計された特殊なインターフェイスです。クエリ実行を改良および制御するための豊富なメソッドのセットを提供し、メソッド連鎖のための流暢な API を提供します。インターフェイスには、返されるドキュメントの数の制限では `limit()`、ページ分割では `skip()`、結果の順序付けでは `sort()`、特定のフィールドの選択では `projection()`、インデックスの選択では `hint()` など、必須のクエリ変更メソッドが含まれています。`FindIterable` のバッチ、スキップ、および制限オペレーションは、データベースからドキュメントを取得して処理する方法を制御するのに役立つ重要なページ分割およびデータ管理ツールです。

バッチ処理 (`batchSize`) は、1 回のネットワークラウンドトリップで DocumentDB がクライアントに返すドキュメントの数を制御します。バッチサイズを設定すると、DocumentDB は一致するすべてのドキュメントを一度に返すのではなく、指定されたバッチサイズのグループで返します。

スキップを使用すると、結果の開始点をオフセットできます。基本的には、一致を返す前に、指定した数のドキュメントをスキップするように DocumentDB に指示します。例えば、`skip(20)` は一致する最初の 20 個のドキュメントをバイパスします。これは、後続の結果ページを取得するページ分割シナリオで一般的に使用されます。

制限は、クエリから返すことができるドキュメントの総数を制限します。`limit(n)` を指定すると、データベースにより多くの一致がある場合でも、DocumentDB は「n」ドキュメントを返した後でドキュメントの返しを停止します。

`FindIterable` は、Amazon DocumentDB からドキュメントを取得するときに、イテレーターパターンとカーソルパターンの両方をサポートします。イテレーターとして `FindIterable` を使用する利点は、ドキュメントの遅延ロードを許可し、アプリケーションから要求された場合にのみドキュメントを取得することです。イテレーターを使用するもう 1 つの利点は、クラスターへの接続を維持する責任がないため、接続を明示的に閉じる必要がないことです。

`FindIterable` は、Amazon DocumentDB クエリを操作するときにカーソルパターンを使用できるようにする [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) のサポートも提供します。`MongoCursor` は、データベースオペレーションとリソース管理を制御する MongoDB Java ドライバー固有の実装です。`AutoCloseable` インターフェイスを実装しているため、try-with-resources ブロックによる明示的なリソース管理が可能になります。これは、データベース接続を適切に閉じ、サーバーリソースを解放するために不可欠です。デフォルトでは、カーソルは 10 分でタイムアウトし、DocumentDB はこのタイムアウト動作を変更するオプションを提供しません。バッチ処理されたデータを使用する場合は、カーソルがタイムアウトする前に、必ず次のデータのバッチを取得してください。`MongoCursor` を使用する際の 1 つの重要な考慮事項は、リソースリークを防ぐために明示的な閉鎖が必要であることです。

このセクションでは、`find()`、`Filters`、および `FindIterable` の例をいくつか示します。

次のコード例は、`find()` を使用して、「restaurantId」フィールドを使用して単一のドキュメントを取得する方法を示しています。

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

`Filters` を使用するとコンパイル時のエラーチェックが向上しますが、Java ドライバーでは `find()` メソッドで直接 `Bson` フィルターを指定することもできます。次のコード例では、`Bson` ドキュメントを `find()` に渡します。

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

次のコード例は、`find()` で `Filters` クラスを使用するいくつかの例を示しています。

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

次の例は、`FindIterable` オブジェクトで `sort()`、`skip()`、`limit()`、および `batchSize()` のオペレーションを連鎖する方法を示しています。これらのオペレーションがどのように提供されるかの順序は、クエリのパフォーマンスに影響します。ベストプラクティスとして、これらのオペレーションの順序は `sort()`、`projection()`、`skip()`、`limit()` および `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);
```

次の例のコードは、`FindIterable` でのイテレーターを作成を示しています。Java の `forEach` コンストラクトを使用して、結果セットをトラバースします。

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

最後の `find()` コード例では、`cursor()` を使用してドキュメントを取得する方法を示しています。試行ブロックにカーソルが作成され、コードが試行ブロックを終了するとカーソルが閉じられます。

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

## DocumentDB コレクション内の既存のドキュメントの更新
<a name="updating-documents"></a>

Amazon DocumentDB は、既存のドキュメントを変更し、存在しないときに新しいドキュメントを挿入するための柔軟で強力なメカニズムを提供します。MongoDB Java ドライバーには、1 つのドキュメントの更新のための `updateOne()`、複数のドキュメントの更新のための `updateMany()`、完全なドキュメント置換のための `replaceOne()` など、複数の更新メソッドが用意されています。これらの 3 つのメソッドに加えて、[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)、[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) は、MongoDB Java ドライバーでの更新オペレーションの構成要素を提供するその他の基本的なコンポーネントです。

MongoDB Java ドライバーの `Updates` クラスは、更新演算子を作成するための静的ファクトリメソッドを提供するユーティリティクラスです。これは、タイプセーフで読み取り可能な方法で更新オペレーションを構築するためのプライマリビルダーとして機能します。`set()`、`unset()`、`inc()` などの基本的なメソッドでは、ドキュメントを直接変更できます。このクラスの能力は、複数の更新オペレーションをアトミックに実行できる `Updates.combine()` メソッドを使用して複数のオペレーションを組み合わせると明らかになり、データ整合性が確保されます。

`UpdateOptions` は、ドキュメント更新オペレーションに不可欠なカスタマイズ機能を提供する MongoDB の Java ドライバーの強力な設定クラスです。このクラスの 2 つの重要な点は、更新オペレーションのアップサートと配列フィルターのサポートを提供することです。`upsert(true)` を介して有効になっているアップサート機能を使用すると、更新オペレーション中に一致するドキュメントが見つからなかった場合に、新しいドキュメントを作成できます。`arrayFilters()` を通じて、更新オペレーションは特定の基準を満たす配列要素を正確に更新できます。

MongoDB の Java ドライバーの `UpdateResult` は、更新オペレーションの結果を詳述するフィードバックメカニズムを提供します。このクラスは、更新基準に一致するドキュメントの数 (`matchedCount`)、実際に変更されたドキュメントの数 (`modifiedCount`)、およびアップサートされたドキュメントに関する情報 (`upsertedId`) の 3 つの主要なメトリクスをカプセル化します。これらのメトリクスを理解することは、適切なエラー処理、更新オペレーションの検証、アプリケーションのデータ整合性の維持に不可欠です。

### 1 つのドキュメントを更新して置き換える
<a name="update-single-doc"></a>

DocumentDB では、updateOne() メソッドを使用して 1 つのドキュメントを更新できます。このメソッドは、通常は `Filters` クラスによって提供されるフィルターパラメータを使用して、更新するドキュメントを識別し、どのフィールド (複数可) を更新するかを決定する `Updat`e パラメータと、更新のさまざまなオプションを設定するオプションの `UpdateOptions` パラメータを使用します。`updateOne()` メソッドを使用すると、選択基準に一致する最初のドキュメントのみが更新されます。次のコード例では、1 つのドキュメントの 1 つのフィールドを更新します。

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

1 つのドキュメント内の複数のフィールドを更新するには、次の例に示すように、`Update.combine()` で `updateOne()` を使用します。この例は、ドキュメント内の配列に項目を追加する方法も示しています。

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

次のコード例は、データベース内のドキュメントを更新する方法を示しています。指定されたドキュメントが存在しない場合、オペレーションはそれを代わりに新しいドキュメントとして自動的に挿入します。このコードは、`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)");
}
```

次のコード例は、個々のフィールドを更新するのではなく、`replaceOne()` メソッドを使用して既存のドキュメントを新しいドキュメントと完全に置き換える方法を示しています。`replaceOne()` メソッドはドキュメント全体を上書きし、元の `_id` フィールドのみを保持します。複数のドキュメントがフィルター条件に一致する場合、最初に検出されたドキュメントのみが置き換えられます。

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

### 複数のドキュメントの更新
<a name="update-multiple-docs"></a>

コレクション内の複数のドキュメントを同時に更新する方法は 2 つあります。`updateMany()` メソッドを使用するか、`bulkWrite()` メソッドの [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) を使用できます。`updateMany()` メソッドは、フィルターパラメータを使用して更新するドキュメントを選択し、`Update` パラメータを使用して更新するフィールドを識別し、オプションの `UpdateOptions` パラメータを使用して更新オプションを指定します。

次のコード例は、`updateMany()` メソッドの使用を示しています。

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

次のコード例は、同じ更新を使用する `bulkWrite()` メソッドを示しています。

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

## DocumentDB コレクションからのドキュメントの削除
<a name="deleting-documents"></a>

MongoDB Java ドライバーは、1 つのドキュメントの削除のために `deleteOne()`、および特定の条件に一致する複数のドキュメントの削除のために `deleteMany()` を提供します。更新と同様に、削除オペレーションは `bulkWrite()` メソッドでも使用できます。`deleteOne()` と `deleteMany()` はどちらも、削除されたドキュメントの数など、オペレーションの結果に関する情報を提供する [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) オブジェクトを返します。`deleteMany()` を使用して複数のドキュメントを削除する例を次に示します。

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

## 再試行ロジックによるエラー処理
<a name="error-handling"></a>

Amazon DocumentDB の堅牢なエラー処理戦略では、エラーを再試行可能 (ネットワークタイムアウト、接続の問題など) と再試行不可能 (認証の失敗、無効なクエリなど) に分類する必要があります。再試行する必要があるエラーによるオペレーションの失敗については、各再試行間の遅延と最大再試行回数を実装する必要があります。CRUD オペレーションは、[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) とそのサブクラスをキャッチする try-catch ブロックにある必要があります。さらに、運用上の可視性のためにエラーのモニタリングとログ記録を含める必要があります。以下は、再試行エラー処理を実装する方法を示すサンプルコードです。

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