翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。
Java を使用した Amazon DocumentDB での CRUD オペレーションの実行
このセクションでは、MongoDB Java ドライバーを使用して Amazon DocumentDB で CRUD (作成、読み取り、更新、削除) オペレーションを実行する方法について説明します。
トピック
DocumentDB コレクションでのドキュメントの作成と挿入
Amazon DocumentDB にドキュメントを挿入すると、コレクションに新しいデータを追加できるようになります。挿入を実行するには、ニーズと使用しているデータの量に応じて、いくつかの方法があります。個々のドキュメントをコレクションに挿入するための最も基本的なメソッドは insertOne() です。一度に複数のドキュメントを挿入するには、insertMany() メソッドを使用できます。これにより、ドキュメントの配列を 1 回のオペレーションで追加できます。DocumentDB コレクションに多くのドキュメントを挿入するもう 1 つのメソッドは bulkWrite() です。このガイドでは、DocumentDB コレクションでドキュメントを作成するためのこれらのすべてのメソッドについて説明します。
insertOne()
まず、個々のドキュメントを Amazon DocumentDB コレクションに挿入する方法を見てみましょう。単一のドキュメントを挿入するには、insertOne() メソッドを使用します。このメソッドは、挿入のために BsonDocumentInsertOneResult
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 を取得するために使用できる InsertManyResultInsertManyResult オブジェクトを返します。
// 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());
bulkWrite() メソッドを使用すると、複数の書き込みオペレーション (挿入、更新、削除) を 1 つのバッチで実行できます。bulkWrite() は、一部のドキュメントを挿入して他のドキュメントを更新するなど、1 つのバッチでさまざまなタイプのオペレーションを実行する必要がある場合に使用できます。bulkWrite() は、順序付きと順序なしの 2 種類のバッチ書き込みをサポートしています。
順序付けられたオペレーション — (デフォルト) Amazon DocumentDB は書き込みオペレーションを順番に処理し、最初に発生したエラーで停止します。これは、後のオペレーションが以前のオペレーションに依存する場合など、オペレーションの順序が重要な場合に役立ちます。ただし、順序付けられたオペレーションは、通常、順序付けられていないオペレーションよりも遅くなります。順序付けられたオペレーションでは、バッチが最初のエラーで停止し、一部のオペレーションが未処理のままになる可能性があるケースに対処する必要があります。
順序付けされていないオペレーション — Amazon DocumentDB が挿入をデータベース内の 1 回の実行として処理できるようにします。1 つのドキュメントでエラーが発生した場合、オペレーションは残りのドキュメントで続行されます。これは、大量のデータを挿入していて、キーの重複が原因で一部のドキュメントが失敗する可能性のあるデータ移行や一括インポートなど、一部の障害を許容できる場合に特に便利です。順序付けされていないオペレーションでは、一部のオペレーションが成功し、他のオペレーションが失敗する部分的な成功シナリオに対処する必要があります。
bulkWrite() メソッドを使用する場合、必須のクラスがいくつかあります。まず、WriteModelInsertOneModelUpdateOneModelUpdateManyModelDeleteOneModelDeleteManyModel
BulkWriteOptionsBulkWriteResult
エラー処理では、MongoBulkWriteExceptionBulkWriteErrorbulkWrite() メソッド呼び出しの実行中に、ドキュメントのリストを挿入し、1 つのドキュメントを更新および削除する例を示しています。このコードは、BulkWriteOptionsBulkWriteResultbulkWrite() オペレーションの適切なエラー処理も示します。
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 は再試行可能な書き込みをサポートしていません。そのため、特にネットワークの問題や一時的なサービス利用不能を処理するために、アプリケーションにカスタム再試行ロジックを実装する必要があります。適切に実装された再試行戦略では、通常、再試行間の遅延を増やし、再試行の合計数を制限します。エラー処理を使用して再試行ロジックを構築するコードサンプルについては、以下の 再試行ロジックによるエラー処理 を参照してください。
DocumentDB コレクションからのデータの読み取りと取得
Amazon DocumentDB でのドキュメントのクエリは、データを正確に取得して操作できるいくつかの主要なコンポーネントを中心に展開されます。find()find() メソッドに加えて、FiltersFindIterable
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 クエリを操作するときにカーソルパターンを使用できるようにする MongoCursorMongoCursor は、データベースオペレーションとリソース管理を制御する 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 コレクション内の既存のドキュメントの更新
Amazon DocumentDB は、既存のドキュメントを変更し、存在しないときに新しいドキュメントを挿入するための柔軟で強力なメカニズムを提供します。MongoDB Java ドライバーには、1 つのドキュメントの更新のための updateOne()、複数のドキュメントの更新のための updateMany()、完全なドキュメント置換のための replaceOne() など、複数の更新メソッドが用意されています。これらの 3 つのメソッドに加えて、UpdatesUpdateOptionsUpdateResult
MongoDB Java ドライバーの Updates クラスは、更新演算子を作成するための静的ファクトリメソッドを提供するユーティリティクラスです。これは、タイプセーフで読み取り可能な方法で更新オペレーションを構築するためのプライマリビルダーとして機能します。set()、unset()、inc() などの基本的なメソッドでは、ドキュメントを直接変更できます。このクラスの能力は、複数の更新オペレーションをアトミックに実行できる Updates.combine() メソッドを使用して複数のオペレーションを組み合わせると明らかになり、データ整合性が確保されます。
UpdateOptions は、ドキュメント更新オペレーションに不可欠なカスタマイズ機能を提供する MongoDB の Java ドライバーの強力な設定クラスです。このクラスの 2 つの重要な点は、更新オペレーションのアップサートと配列フィルターのサポートを提供することです。upsert(true) を介して有効になっているアップサート機能を使用すると、更新オペレーション中に一致するドキュメントが見つからなかった場合に、新しいドキュメントを作成できます。arrayFilters() を通じて、更新オペレーションは特定の基準を満たす配列要素を正確に更新できます。
MongoDB の Java ドライバーの UpdateResult は、更新オペレーションの結果を詳述するフィードバックメカニズムを提供します。このクラスは、更新基準に一致するドキュメントの数 (matchedCount)、実際に変更されたドキュメントの数 (modifiedCount)、およびアップサートされたドキュメントに関する情報 (upsertedId) の 3 つの主要なメトリクスをカプセル化します。これらのメトリクスを理解することは、適切なエラー処理、更新オペレーションの検証、アプリケーションのデータ整合性の維持に不可欠です。
1 つのドキュメントを更新して置き換える
DocumentDB では、updateOne() メソッドを使用して 1 つのドキュメントを更新できます。このメソッドは、通常は Filters クラスによって提供されるフィルターパラメータを使用して、更新するドキュメントを識別し、どのフィールド (複数可) を更新するかを決定する Update パラメータと、更新のさまざまなオプションを設定するオプションの 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());
複数のドキュメントの更新
コレクション内の複数のドキュメントを同時に更新する方法は 2 つあります。updateMany() メソッドを使用するか、bulkWrite() メソッドの UpdateManyModelupdateMany() メソッドは、フィルターパラメータを使用して更新するドキュメントを選択し、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 コレクションからのドキュメントの削除
MongoDB Java ドライバーは、1 つのドキュメントの削除のために deleteOne()、および特定の条件に一致する複数のドキュメントの削除のために deleteMany() を提供します。更新と同様に、削除オペレーションは bulkWrite() メソッドでも使用できます。deleteOne() と deleteMany() はどちらも、削除されたドキュメントの数など、オペレーションの結果に関する情報を提供する DeleteResultdeleteMany() を使用して複数のドキュメントを削除する例を次に示します。
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());
再試行ロジックによるエラー処理
Amazon DocumentDB の堅牢なエラー処理戦略では、エラーを再試行可能 (ネットワークタイムアウト、接続の問題など) と再試行不可能 (認証の失敗、無効なクエリなど) に分類する必要があります。再試行する必要があるエラーによるオペレーションの失敗については、各再試行間の遅延と最大再試行回数を実装する必要があります。CRUD オペレーションは、MongoException
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); } }