Java を使用した Amazon DocumentDB での CRUD オペレーションの実行 - Amazon DocumentDB

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

Java を使用した Amazon DocumentDB での CRUD オペレーションの実行

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

DocumentDB コレクションでのドキュメントの作成と挿入

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

insertOne()

まず、個々のドキュメントを Amazon DocumentDBB コレクションに挿入する方法を見てみましょう。単一のドキュメントを挿入するには、 insertOne()メソッドを使用します。このメソッドは、挿入のために BsonDocument を取得し、新しい挿入されたドキュメントのInsertOneResultオブジェクト ID を取得するために使用できるオブジェクトを返します。以下のコード例は、コレクションに 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() 関数は、挿入されたすべてのドキュメントの IDsを取得するために使用できる 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()

bulkWrite() メソッドを使用すると、複数の書き込みオペレーション (挿入、更新、削除) を 1 つのバッチで実行できます。は、一部のドキュメントを挿入して他のドキュメントを更新するなど、1 つのバッチでさまざまなタイプのオペレーションを実行bulkWrite()する必要がある場合に使用できます。 は、順序付きと順序なしの 2 種類のバッチ書き込みbulkWrite()をサポートしています。

  • 順序付けられたオペレーション — (デフォルト) Amazon DocumentDB は書き込みオペレーションを順番に処理し、最初に発生したエラーで停止します。これは、後のオペレーションが以前のオペレーションに依存する場合など、オペレーションの順序が重要な場合に役立ちます。ただし、順序付けられたオペレーションは、通常、順序付けられていないオペレーションよりも遅くなります。順序付けられたオペレーションでは、バッチが最初のエラーで停止し、一部のオペレーションが未処理のままになる可能性があるケースに対処する必要があります。

  • 順序付けされていないオペレーション — Amazon DocumentDB が挿入をデータベース内の 1 回の実行として処理できるようにします。1 つのドキュメントでエラーが発生した場合、オペレーションは残りのドキュメントで続行されます。これは、大量のデータを挿入していて、キーの重複が原因で一部のドキュメントが失敗する可能性のあるデータ移行や一括インポートなど、一部の障害を許容できる場合に特に便利です。順序付けされていないオペレーションでは、一部のオペレーションが成功し、他のオペレーションが失敗する部分的な成功シナリオに対処する必要があります。

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

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

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

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() メソッドは、MongoDB Java ドライバーの基本的なクエリ APIs。これにより、フィルタリング、ソート、結果の射影のための多数のオプションを使用して、複雑なデータ取得が可能になります。find() メソッドに加えて、 FiltersFindIterableは、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 は一致するすべてのドキュメントを一度に返すのではなく、指定されたバッチサイズのグループで返します。

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

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

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

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

このセクションでは、、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", "$$"))))

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

FindIterable < Document > results; // Exact match results = collection.find(Filters.eq("name", "Thai Curry Palace")); // Not equal results = collection.find(Filters.ne("cuisine", "Thai")); // find an element in an array results = collection.find(Filters.in("features", Arrays.asList("Private Dining"))); // Greater than results = collection.find(Filters.gt("rating.average", 3.5)); // Between (inclusive) results = collection.find(Filters.and( Filters.gte("rating.totalReviews", 100), Filters.lte("rating.totalReviews", 200))); // AND results = collection.find(Filters.and( Filters.eq("cuisine", "Thai"), Filters.gt("rating.average", 4.5))); // OR results = collection.find(Filters.or( Filters.eq("cuisine", "Thai"), Filters.eq("cuisine", "American"))); // All document where the Field exists results = collection.find(Filters.exists("michelin")); // Regex results = collection.find(Filters.regex("name", Pattern.compile("Curry", Pattern.CASE_INSENSITIVE))); // Find all document where the array contain the list of value regardless of its order results = collection.find(Filters.all("features", Arrays.asList("Private Dining", "Parking"))); // Array size results = collection.find(Filters.size("features", 4));

次の例は、 FindIterable オブジェクトbatchSize()に対する sort()、、limit()、および skip()のオペレーションを連鎖する方法を示しています。これらのオペレーションがどのように提供されるかの順序は、クエリのパフォーマンスに影響します。ベストプラクティスとして、これらのオペレーションの順序は 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 つのドキュメントの更新、updateMany()複数のドキュメントの更新、replaceOne()完全なドキュメント置換updateOne()の複数の更新方法が用意されています。これら 3 つのメソッドに加えて、、UpdateOptionsUpdateResultUpdates、MongoDB Java ドライバーの更新オペレーションの構成要素を提供するその他の基本的なコンポーネントです。

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

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

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

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()メソッドUpdateManyModelで を使用できます。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 コレクションからのドキュメントの削除

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

再試行ロジックによるエラー処理

Amazon DocumentDB の堅牢なエラー処理戦略では、エラーを再試行可能 (ネットワークタイムアウト、接続の問題など) と再試行不可能 (認証の失敗、無効なクエリなど) に分類する必要があります。再試行する必要があるエラーによるオペレーションの失敗の場合、各再試行と最大再試行回数の間に時間遅延を実装する必要があります。CRUD オペレーションは、 MongoExceptionとそのサブクラスをキャッチする 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); } }