

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

# Amazon DocumentDB Java プログラミングガイド
<a name="docdb-java-pg"></a>

この包括的なガイドでは、MongoDB の Java ドライバーを使用して Amazon DocumentDB を操作するための詳細なウォークスルーを提供し、データベースの運用と管理の重要な側面について説明します。

**Topics**
+ [

## 序章
](#java-pg-intro)
+ [

## 前提条件
](#java-pg-prereqs)
+ [データモデル](#java-pg-data-models)
+ [Java ドライバーとの接続](java-pg-connect-mongo-driver.md)
+ [Java を使用した CRUD オペレーション](java-crud-operations.md)
+ [Java によるインデックス管理](index-management-java.md)
+ [イベント駆動型プログラミング](event-driven-programming.md)

## 序章
<a name="java-pg-intro"></a>

このガイドは接続から始まり、MongoDB Java ドライバーを使用して DocumentDB クラスターへの安全な接続を確立する方法について説明します。接続文字列コンポーネント、SSL/TLS 実装、IAM 認証や接続プーリングなどのさまざまな接続オプション、堅牢なエラー処理戦略について詳しく説明します。

CRUD (作成、読み取り、更新、削除) オペレーションセクションでは、このガイドでドキュメントの操作について詳しく説明し、単一オペレーションと一括オペレーションの両方を使用してドキュメントの作成、読み取り、更新、削除を行う方法を示します。ここでは、フィルター、クエリ、およびさまざまなオペレーションオプションの使用について説明し、エラー処理のベストプラクティスと信頼性を向上させるための再試行ロジックの実装に焦点を当てています。このガイドでは、単一フィールドインデックス、複合インデックス、スパースインデックス、テキストインデックスなど、さまざまなインデックスタイプの作成とメンテナンスについて詳しく説明しています。適切なインデックス選択と、クエリ実行プランを分析するための `explain()` 関数の使用を通じてクエリパフォーマンスを最適化する方法について説明します。

最後のセクションでは、Amazon DocumentDB の変更ストリームを使用したイベント駆動型プログラミングに焦点を当て、Java アプリケーションでリアルタイムのデータ変更モニタリングを実装する方法を示します。変更ストリームカーソルの実装、継続的オペレーションの再開トークンの処理、履歴データ処理の時間ベースのオペレーションについて説明します。ガイド全体で、実用的なコード例とベストプラクティスが提供されるため、Amazon DocumentDB で堅牢な Java アプリケーションを構築する際の貴重なリソースとなります。

## 前提条件
<a name="java-pg-prereqs"></a>

作業を開始する前に、次の項目があることを確認します。
+ DocumentDB クラスターが設定された AWS アカウント。DocumentDB クラスターのセットアップについては、この [入門ブログ記事](https://aws.amazon.com/blogs/database/part-1-getting-started-with-amazon-documentdb-using-amazon-ec2/) を参照してください。
+ Java Development Kit (JDK) がインストールされている (このガイドでは [Amazon Corretto 21](https://docs.aws.amazon.com/corretto/latest/corretto-21-ug/downloads-list.html) を使用します)。
+ 依存関係管理のための Maven。

## このガイドのデータモデル
<a name="java-pg-data-models"></a>

このガイドのすべてのサンプルコードは、「Restaurants」コレクションを持つ「ProgGuideData」テストデータベースへの接続を前提としています。このガイドのすべてのサンプルコードは、レストラン出品システムで動作します。以下は、このシステムのドキュメントの例です。

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

CRUD、インデックス管理、イベント駆動型プログラミングを示すすべてのコードサンプルは、[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`、[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`、および [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` があることを前提としています。

**注記**  
このガイドのすべてのコード例は、MongoDB Java ドライバーバージョン 5.3.0 でテストされています。

# MongoDB Java ドライバーを使用した Amazon DocumentDB への接続
<a name="java-pg-connect-mongo-driver"></a>

このセクションでは、Java ドライバーを使用して Amazon DocumentDB に接続するためのステップバイステップのガイドを提供します。これにより、DocumentDB を Java アプリケーションへの統合を開始できるようになります。

**Topics**
+ [

## ステップ 1: プロジェクトをセットアップする
](#step1-set-up)
+ [

## ステップ 2: 接続文字列を作成する
](#step2-create-connection-string)
+ [

## ステップ 3: 接続コードを書き込む
](#step3-write-connect-code)
+ [

## ステップ 4: 接続例外を処理する
](#step4-handle-connect-exceptions)
+ [

## ステップ 5: コードの実行
](#step5-running-code)
+ [

## 接続のベストプラクティス
](#java-connect-best-practices)

## ステップ 1: プロジェクトをセットアップする
<a name="step1-set-up"></a>

1. Maven を使用して、Java プロジェクトを作成します。

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

1. MongoDB Java ドライバーをプロジェクトの依存関係として「pom.xml」ファイルに追加します。

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

## ステップ 2: 接続文字列を作成する
<a name="step2-create-connection-string"></a>

Amazon DocumentDB 接続文字列は、アプリケーションと DocumentDB クラスター間の接続を確立するために不可欠です。この文字列は、クラスターエンドポイント、ポート、認証の詳細、さまざまな接続オプションなどの重要な情報をカプセル化します。DocumentDB 接続文字列を構築するには、通常、基本的な形式から始めます。

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

「username」と「password」を実際の認証情報に置き換える必要があります。クラスターのエンドポイントとポート番号は、 AWS マネジメントコンソール だけでなく、 からも確認できます AWS CLI。クラスターのクラスターエンドポイントを見つけるには、「[クラスターのエンドポイントの検索](db-cluster-endpoints-find.md)」を参照してください。DocumentDB のデフォルトのポートは、27017 です。

**接続文字列の例**
+ 転送中の暗号化を使用して DocumentDB に接続し、読み取りリクエストがリードレプリカに送信され、プライマリに書き込まれることを確認します。

  ```
  "mongodb://username:password@cluster-endpoint:27017/?tls=true& 
     tlsCAFile=global-bundle.pem& 
     readPreference=secondaryPreferred&
     retryWrites=false"
  ```
+ IAM 認証を使用して DocumentDB に接続する:

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

接続文字列で使用できるさまざまなオプションは次のとおりです。
+ [TLS 証明書](#connection-string-tls)
+ [リードレプリカからの読み取り](#connection-string-read-rep)
+ [ライトコンサーンとジャーナリング](#connection-string-write-journal)
+ [RetryWrites](#connection-string-retry-writes)
+ [IAM 認証](#connection-string-iam-auth)
+ [接続プール](#connection-string-pool)
+ [接続タイムアウトパラメータ](#connection-string-timeout)

### TLS 証明書
<a name="connection-string-tls"></a>

**`tls=true|false`** — このオプションは Transport Layer Security (TLS) を有効または無効にします。デフォルトでは、転送中の暗号化は Amazon DocumentDB クラスターで有効になっているため、クラスターレベルで TLS が無効になっていない限り、このオプションの値は `true` である必要があります。

TLS を使用する場合、コードは DocumentDB クラスターへの接続を作成するときに SSL 証明書を提供する必要があります。クラスターへの安全な接続に必要な証明書をダウンロードします: [https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem](https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem)。`global-bundle.pem` ファイルを使用するには 2 つの方法があります。
+ **オプション 1** — `global-bundle.pem` ファイルからすべての証明書を抽出し、Java の keytool を使用して、後でコードで使用できる `.jks` ファイルに保存します。これを行う方法を示すスクリプトについては、[TLS が有効な場合の接続](connect_programmatically.md#connect_programmatically-tls_enabled) の Java タブを参照してください。
+ **オプション 2** — `global-bundle.pem` ファイルをコードに動的に追加し、インメモリキーストアを構築し、`SSLContext` を使用して接続の一部として証明書を提供します。

### リードレプリカからの読み取り
<a name="connection-string-read-rep"></a>

**`replicaSet=rs0&readPreference=secondaryPreferred`** — これら 2 つのオプションを指定すると、すべての読み取りリクエストがリードレプリカにルーティングされ、書き込みリクエストがプライマリインスタンスにルーティングされます。接続文字列で `replicaSet=rs0` を使用すると、MongoDB ドライバーはクラスタートポロジの自動更新ビューを維持できるため、インスタンスの追加または削除時にアプリケーションが現在のノード設定の可視性を維持できます。これらのオプションを提供しない場合、または `readPreference=primary` を指定しない場合、すべての読み取りと書き込みがプライマリインスタンスに送信されます。`readPreference` のオプションについては、「[読み込み設定のオプション](how-it-works.md#durability-consistency-isolation)」を参照してください。

### ライトコンサーンとジャーナリング
<a name="connection-string-write-journal"></a>

書き込みの懸念は、書き込みオペレーションのためにデータベースからリクエストされた確認のレベルを決定します。MongoDB ドライバーには、書き込みの懸念ファイルとジャーナルファイルを調整するオプションがあります。Amazon DocumentDB では、書き込みの懸念とジャーナルを設定することは想定されておらず、`w` と `j` (`writeConcern` と `journal`) に送信された値は無視されます。DocumentDB は常に `writeConcern`: `majority` および `journal`: `true` でデータを書き込みます。そのため、クライアントに確認を送信する前に、書き込みは大部分のノードに永続的に記録されます。

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

**`retryWrites=false`** — DocumentDB は再試行可能な書き込みをサポートしていないため、この属性は常に `false` に設定する必要があります。

### IAM 認証
<a name="connection-string-iam-auth"></a>

**`authSource=%24external` および `authMechanism=MONGODB-AWS`** — この 2 つのパラメータは、 を使用した認証に使用されます AWS Identity and Access Management。IAM 認証は現在、インスタンスベースのクラスターバージョン 5.0 でのみ使用できます。詳細については、「[IAM ID を使用した認証](iam-identity-auth.md)」を参照してください。

### 接続プール
<a name="connection-string-pool"></a>

これらのオプションは、接続プーリングで使用できます。
+ **`maxPoolSize`** — プールに作成できる接続の最大数を設定します。すべての接続が使用されていて、新しいリクエストが入ると、接続が利用可能になるまで待機します。MongoDB Java ドライバーのデフォルトは 100 です。
+ **`minPoolSize`** — プールで常に維持する必要がある接続の最小数を示します。MongoDB Java ドライバーのデフォルトは 0 です。
+ **`maxIdleTimeMS`** — 接続を、閉じたり削除したりする前に、プールでアイドル状態のままにできる時間を決定します。MongoDB Java ドライバーのデフォルトは 100 ミリ秒です。
+ **`waitQueueTimeoutMS`** — プールが最大サイズになったときに、接続が利用可能になるまでスレッドが待機する時間を設定します。この時間内に接続が利用可能にならない場合は、例外がスローされます。MongoDB Java ドライバーのデフォルト値は 120,000 ミリ秒 (2 分) です。

### 接続タイムアウトパラメータ
<a name="connection-string-timeout"></a>

タイムアウトは、オペレーションまたは接続の試行が失敗したと見なされるまでにかかる時間を制限するメカニズムです。次のタイムアウトパラメータは、無期限の待機を防ぎ、リソース割り当てを管理するために使用できます。
+ **`connectTimeoutMS`** — ドライバーがクラスターへの接続を確立するのを待機する時間を設定します。デフォルトは 10,000 ミリ秒 (10 秒) です。
+ **`socketTimeoutMS`** — ドライバーがサーバーからの非書き込みオペレーションのレスポンスを待機する時間を指定します。デフォルトは 0 (タイムアウトまたは無限なし) です。
+ **`serverSelectionTimeoutMS`** — ドライバーがクラスター内の使用可能なサーバーを見つけるまで待機する時間を指定します。この設定のデフォルト値は 30 秒で、フェイルオーバー中に新しいプライマリインスタンスを選択するのに十分です。

## ステップ 3: 接続コードを書き込む
<a name="step3-write-connect-code"></a>

次のコード例は、Amazon DocumentDB への TLS 接続を行う方法を示しています。
+ 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) および [`SSLContext`>](https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLContext.html) オブジェクトが作成されます。
+ また、[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) オブジェクトに渡すことで [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) オブジェクトを作成します。TLS 接続を行うには、 `MongoClientSettings` オブジェクトを使用して `connectionstring` と `sslcontext` をバインドする必要があります。
+ [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) を使用すると、 [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);
    }
}
```

## ステップ 4: 接続例外を処理する
<a name="step4-handle-connect-exceptions"></a>

Java アプリケーションで DocumentDB を使用する場合、堅牢で信頼性の高いデータベースオペレーションを維持するには、接続例外の処理が不可欠です。これらの例外を適切に管理することで、問題を迅速に診断できるだけでなく、アプリケーションが一時的なネットワーク中断やサーバーの非可用性を正常に処理できるため、安定性とユーザーエクスペリエンスが向上します。接続の確立に関連する重要な例外には、次のようなものがあります。
+ **`MongoException`** — 一般的な例外であり、より具体的な例外の対象ではないさまざまなシナリオで発行される場合があります。これは一般的なすべての MongoDB 例外のキャッチであるため、この例外は他のすべての特定の例外の後に処理されることを確認してください。
+ **`MongoTimeoutException`** — オペレーションがタイムアウトしたときに発行されます。例えば、存在しないクラスターエンドポイントのクエリなどです。
+ **`MongoSocketException`** — ネットワーク関連の問題に対して発行されます。例えば、オペレーション中の突然のネットワーク切断などです。
+ **`MongoSecurityException`** — 認証が失敗した場合に発行されます。例えば、誤った認証情報での接続などです。
+ **`MongoConfigurationException`** — クライアント設定にエラーがある場合に発行されます。例えば、無効な接続文字列の使用などです。

## ステップ 5: コードの実行
<a name="step5-running-code"></a>

次のコードサンプルは、Amazon DocumentDB 接続を作成し、すべてのデータベースを出力します。

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

## 接続のベストプラクティス
<a name="java-connect-best-practices"></a>

以下は、MongoDB Java ドライバーを使用して Amazon DocumentDB に接続するときに考慮すべきベストプラクティスです。
+ クライアントにリソースを解放してもらう必要がなくなった場合は、必ず [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) を閉じてください。
+ 例外を適切に処理し、適切なエラーログ記録を実装します。
+ 環境変数または を使用して AWS Secrets Manager 、ユーザー名やパスワードなどの機密情報を保存します。

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

# Java による Amazon DocumentDB でのインデックス管理
<a name="index-management-java"></a>

インデックスを使用すると、Amazon DocumentDB コレクションからデータを効率的に取得できます。インデックスがない場合、DocumentDB はコレクション内のすべてのドキュメントをスキャンして、特定のクエリを満たす結果を返す必要があります。このトピックでは、MongoDB Java ドライバーを使用してインデックスを作成、削除、および一覧表示する方法について説明します。また、クエリで特定のインデックスが使用されているかどうかを判断する方法と、特定のインデックスを使用するように Amazon DocumentDB にヒントを与える方法について説明します。

**Topics**
+ [インデックスの作成](#creating-indexes)
+ [インデックスの削除](#dropping-indes)
+ [インデックス選択の決定とインデックスヒントの提供](#w2aac43b9b7c17c13)

Amazon DocumentDB は、多くのタイプのインデックスをサポートしています。サポートされているすべてのインデックスの包括的な概要については、この [ブログ記事](https://aws.amazon.com/blogs/database/how-to-index-on-amazon-documentdb-with-mongodb-compatibility/) を参照してください。

## Java によるインデックスの作成
<a name="creating-indexes"></a>

MongoDB Java ドライバーを使用して Amazon DocumentDB でインデックスを作成するメカニズムには、`runCommand()` を通じたもの、および単一のインデックスでの `createIndex()` メソッドまたは複数のインデックスでの `createIndexes()` メソッドのいずれかによるものの 2 つがあります。`createIndex()` および `createIndexes()` メソッドを使用する理由の 1 つは、インデックス作成に関連する特定のエラーをキャッチすることで、より良いエラー処理を構築できることです。これらのメソッドを `runCommand()` で使用するもう 1 つの理由は、MongDB Java ドライバーがインデックスの作成と操作のための豊富なサポートクラスを提供することです。これらのサポートクラスは、`createIndex()` または `createIndexes()` メソッドを使用している場合にのみ使用できることに注意してください。3 つのサポートクラスがあります。
+ **[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)** — このクラスは、さまざまなタイプのインデックスを作成するための静的ファクトリメソッドを提供するユーティリティクラスとして機能します。これにより、複雑なインデックス定義を作成するプロセスが簡素化され、一般的に他のインデックス関連クラスと組み合わせて使用されます。
+ **[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)** — これは、インデックスキー定義とそのオプションの両方をカプセル化する基本的なクラスです。これは、インデックスを作成する内容 (キー) とインデックスを作成する方法 (オプション) を組み合わせた完全なインデックス仕様を表します。このクラスは、`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)** — これは、インデックスの動作をカスタマイズするための豊富なメソッドのセットを提供する包括的な設定クラスです。これには、一意のインデックス、スパースインデックス、有効期限 (TTL)、および部分フィルター式の設定が含まれます。メソッドチェーンを使用すると、バックグラウンドインデックスの構築や一意の制約など、複数のオプションを設定できます。

**単一のインデックスを作成する**

この例では、バックグラウンドで `createIndex(`) メソッドを使用して単一のインデックスを作成する方法を示します。バックグラウンドインデックスとフォアグラウンドインデックスの作成については、「[インデックスビルドのタイプ](managing-indexes.md#index-build-types)」を参照してください。次のコード例では、[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) を使用して、バックグラウンドで「unique\$1restaurantId\$1idx」という名前の一意のインデックスを作成します。その後、この `IndexOptions` オブジェクトは `createIndex()` メソッドに渡されます。

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

**複数のインデックスを作成する**

この例では、`createIndexes()` メソッドを使用して複数のインデックスを作成します。まず、[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) オブジェクトを使用して各インデックスのオプションを構築し、次に `IndexModel` オブジェクトのリストを `createIndexes()` メソッドに渡します。次のコード例は、[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) ユーティリティクラスを使用して複合インデックスを作成する方法を示しています。このクラスは、昇順または降順のソート順序を使用してインデックスを作成するかどうかを指定するためにも使用されます。複数のインデックスを作成した後、`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()));
```

**スパースインデックスと部分インデックスを作成する**

この例では、インデックスのタイプごとに [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) を作成して、スパースインデックスと部分インデックスを作成する方法を示します。

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

**テキストインデックスを作成する**

この例では、テキストインデックスを作成する方法を示します。コレクションでは 1 つのテキストインデックスのみが許可されますが、1 つのテキストインデックスを複数のフィールドをカバーする複合インデックスにすることができます。テキストインデックスで複数のフィールドを使用する場合、インデックス内の各フィールドに重みを割り当てることもできます。配列フィールドのテキストインデックスは Amazon DocumentDB ではサポートされていません。複合テキストインデックスでは最大 30 個のフィールドを使用できますが、重みを割り当てることができるフィールドは 3 つだけです。

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

**`runCommand()` を使用してインデックスを作成する**

Amazon DocumentDB は、インデックスの作成にかかる時間を短縮するための並列インデックス作成をサポートしています。並列インデックス作成は、複数の同時ワーカーを使用します。インデックスの作成に使用されるデフォルトのワーカーは 2 つです。この [ブログ記事](https://aws.amazon.com/blogs/database/unlock-the-power-of-parallel-indexing-in-amazon-documentdb/) では、並列インデックス作成について詳しく説明します。現在、MongDB Java ドライバーは、`createIndex()` または `createIndexes()` を使用しているときにワーカーオプションの指定をサポートしていないため、ワーカーを指定する唯一の方法は `runCommand` を使用することです。次のコード例は、`runCommand` を使用して、ワーカーを 4 つに増やすインデックスを作成する方法を示しています。

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

## インデックスの削除
<a name="dropping-indes"></a>

MongoDB Java ドライバーは、さまざまなシナリオや好みに応じて、インデックスを削除する複数のメソッドを提供します。名前で、またはキー仕様でインデックスを削除するか、すべてのインデックスを一度に削除できます。メソッド `dropIndex()` と `dropIndexes()` をコレクションオブジェクトで呼び出して、インデックスを削除できます。名前でインデックスを削除する場合は、特に複合インデックスまたは自動生成されたインデックスの場合、常に直感的とは限らない正しいインデックス名を使用してください。存在しないインデックスを削除しようとすると、[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) になります。コレクション内でドキュメントの一意性が確保されるため、`default _id` インデックスを削除することはできません。

次のコード例は、インデックスが作成されたフィールド名を指定するか、すべてのインデックスを削除することで、インデックスを削除する方法を示しています。

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

複数のキーを使用してインデックスを削除する場合は、指定されたすべてのキーを含む複合インデックスがあり、キーの順序が正しいことを確認してください。上記のインデックス作成サンプルコード例は、「cuisine」および 機能の複合キーを示しています。その複合キーを削除しようとしても、その順序が作成で使用された順序ではない場合、MongoCommnadException エラーが次のように発生します。

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

次のエラーが表示されます。

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

## インデックス選択の決定とインデックスヒントの提供
<a name="w2aac43b9b7c17c13"></a>

Amazon DocumentDB の説明機能を操作することは、クエリのパフォーマンスとインデックスの使用を理解するために不可欠です。クエリを実行するときは、`explain()` メソッドを追加して、どのインデックスが使用されているか (ある場合) など、クエリプランに関する詳細情報を取得できます。`explain()` 出力は、クエリ実行ステージ、調査されたドキュメントの数、および各ステージにかかる時間に関するインサイトを提供します。この情報は、特定のインデックスが効果的に使用されているかどうか、またはクエリが別のインデックス構造から恩恵を受けることができるかどうかを識別するのに非常に役立ちます。

`explain()` メソッドは、`find()` メソッドと連鎖できます。`explain()` メソッドは、`explain()` によって返される詳細レベルを決定するオプションの [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) 列挙値を取ることができます。現時点では、`EXECUTION_STATS` および `QUERY_PLANNER` 列挙子のみが DocumentDB でサポートされています。次のコード例は、特定のクエリのクエリプランナーを取得する方法を示しています。

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

クエリプランナーの詳細レベルには、次の JSON ドキュメントが返されます。

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

Amazon DocumentDB が特定のインデックスを使用するように影響または強制するには、いくつかのオプションがあります。`hint()` および `hintString()` メソッドでは、クエリに使用するインデックスを明示的に指定することで、クエリオプティマイザのデフォルトのインデックス選択動作を上書きできます。DocumentDB のクエリオプティマイザは通常、インデックスの選択に適切な選択を行いますが、歪んだデータを扱うときやインデックスのパフォーマンスをテストするときなど、特定のインデックスを `hint()` または `hintString()` で強制することが有益なシナリオがあります。

次のコード例では、上記のコードで実行されたのと同じクエリに対して複合インデックス「cuisine\$1features\$1idx」を強制的に使用します。

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

# Amazon DocumentDB と Java を使用したイベント駆動型プログラミング
<a name="event-driven-programming"></a>

Amazon DocumentDB のコンテキストにおけるイベント駆動型プログラミングは、データベースの変更が後続のビジネスロジックとプロセスをトリガーする主要なイベントジェネレーターとして機能する強力なアーキテクチャパターンを表します。DocumentDB コレクションでレコードが挿入、更新、または削除されると、これらの変更はさまざまなダウンストリームプロセス、通知、またはデータ同期タスクを自動的に開始するイベントとして機能します。このパターンは、複数のアプリケーションまたはサービスがデータ変更にリアルタイムで対応する必要がある最新の分散システムでは特に重要です。DocumentDB でイベント駆動型プログラミングを実装する主なメカニズムは、変更ストリームです。

**注記**  
このガイドでは、作業中のコレクションで変更ストリームを有効にしていることを前提としています。コレクションで変更ストリームを有効にする方法については、「[Amazon DocumentDB を用いた変更ストリームの使用](change_streams.md)」を参照してください。

**Java アプリケーションからの変更ストリームの使用**

MongoDB の Java ドライバーの `watch()` メソッドは、Amazon DocumentDB でリアルタイムのデータ変更をモニタリングするための主要なメカニズムです。`watch()` メソッドは、[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))、および [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()) オブジェクトによって呼び出すことができます。

`watch()` メソッドは、更新の完全なドキュメント検索、信頼性のための再開トークンとタイムスタンプの提供、変更をフィルタリングするためのパイプライン集約ステージなど、さまざまな設定オプションをサポートする [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)) のインスタンスを返します。

[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)) はコア Java インターフェイス `Iterable` を実装しており、`forEach()` で使用できます。`forEach()` を使用してイベントをキャプチャするには、変更されたイベントを処理する `forEach()` にコールバック関数を渡します。次のコードスニペットは、コレクションで変更ストリームを開いて変更イベントのモニタリングを開始する方法を示しています。

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

すべての変更イベントを通過するもう 1 つの方法は、クラスターへの接続を維持し、発生時に新しい変更イベントを継続的に受信するカーソルを開くことです。変更ストリームカーソルを取得するには、[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)) オブジェクトの `cursor()` メソッドを使用します。次のコード例は、カーソルを使用して変更イベントをモニタリングする方法を示しています。

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

ベストプラクティスとして、 try-with-resource ステートメントで [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()) を作成するか、カーソルを手動で閉じます。[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)) で `cursor()` メソッドを呼び出すと、[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) オブジェクト上に作成された `MongoChangeStreamCursor` が返されます。

[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) クラスは、ストリーム内の個々の変更イベントを表す重要なコンポーネントです。これには、オペレーションタイプ (挿入、更新、削除、置換)、ドキュメントキー、名前空間情報、および使用可能な場合の完全なドキュメントコンテンツなど、各変更に関する詳細情報が含まれます。クラスは、変更のタイプを決定する `getOperationType()`、完全なドキュメント状態にアクセスする `getFullDocument()`、変更されたドキュメントを識別する `getDocumentKey()` など、変更イベントのさまざまな側面にアクセスするメソッドを提供します。

[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) オブジェクトは、再開トークンと変更イベントという、時刻の 2 つの重要な情報を提供します。

DocumentDB 変更ストリームの再開トークンと時間ベースのオペレーションは、継続性を維持し、履歴データアクセスを管理するための重要なメカニズムを提供します。再開トークンは、変更イベントごとに生成される一意の識別子であり、切断または障害後にアプリケーションが特定のポイントから変更ストリーム処理を再開できるようにするブックマークとして機能します。変更ストリームカーソルを作成すると、`resumeAfter()` オプションを使用して以前に保存した再開トークンを使用できます。これにより、ストリームは最初から開始したり、イベントを失ったりするのではなく、中断した場所から続行できます。

変更ストリームの時間ベースのオペレーションは、変更イベントモニタリングの開始点を管理するためのさまざまなアプローチを提供します。`startAtOperationTime()` オプションを使用すると、特定のタイムスタンプ以降に発生した変更の監視を開始できます。これらの時間ベースの機能は、履歴データ処理、ポイントインタイムリカバリ、またはシステム間の同期を必要とするシナリオで特に役立ちます。

次のコード例は、挿入ドキュメントに関連付けられたイベントを取得し、再開トークンをキャプチャしてから、挿入イベントの後にイベントのモニタリングを開始するトークンを提供します。イベントは更新イベントに関連付けられ、更新が発生したクラスター時間を取得し、そのタイムスタンプをさらなる処理の開始点として使用します。

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

デフォルトで、変更の更新イベントには、ドキュメント全体は含まれず、加えられた変更のみが含まれます。更新した完全なドキュメントにアクセスする必要がある場合は、[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)) オブジェクトで `fullDocument()` メソッドを呼び出すことができます。更新イベントに対して完全なドキュメントが返されるように要求すると、変更ストリームへの呼び出しが行われた時点で存在するドキュメントが返されることに注意してください。

このメソッドは、[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) 列挙型をパラメータとして受け取ります。現在、Amazon DocumentDB は DEFAULT および `UPDATE_LOOKUP` 値のみをサポートしています。次のコードスニペットは、変更の監視を開始するときに、更新イベントの完全なドキュメントを要求する方法を示しています。

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