MongoDB Atlas で回復力のあるアプリケーションを構築
項目一覧
重要なアプリケーションを構築する場合は、本番環境で発生する可能性のある予期しないイベントに備えることが重要です。 これには、予期しない低速クエリ、インデックスの欠落、またはワークロード量の急増が含まれます。
MongoDB Atlasは、先を見越して準備し、状況に対応できるようにする既存の機能を提供することで、回復力のあるアプリケーションを構築するのに役立ちます。 回復力のあるアプリケーションを構築するには、次のクラスターの回復力とアプリケーション、およびクライアント側のベストプラクティスでMongoDBデプロイを構成することをお勧めします。
クラスターの回復力
クラスターの回復力を向上させるには、 クラスターをMongoDB 8.0にアップグレードします。 MongoDB 8.0では、回復力に関連する次のパフォーマンスの向上と新機能が導入されています。
コストのかかるクエリをリアクティブに軽減する操作拒否フィルター
コストのかかる読み取り操作に対するプロアクティブな保護のためのクラスターレベルのタイムアウト
moveCollection コマンドによるワークロードのより優れた分離
メモリ管理の改善
アプリケーションを本番環境で安全に実行するには、ヘッドルームが許容されるメモリ使用率を確認するのが重要です。 ノードの使用可能なメモリが不足すると、 Linuxメモリ不足キーラー mongod
の 影響を受ける可能性があります。 これにより、 プロセスが終了します。
MongoDB 8.0はアップグレードされた TCMallocをすべての配置に自動的に使用するため、平均的なメモリ フラグメントの増加が時間の経過とともに減少します。 フラグメント度が低いことで、ピーク負荷時の動作安定性が向上し、メモリ使用率が全体的に向上します。
操作拒否フィルター
意図しないリソース集中操作は、迅速に処理されない場合、本番環境で問題が発生する可能性があります。
MongoDB 8.0では、操作拒否フィルターを使用して、これらの操作の影響を最小限に抑えることができます。 操作拒否フィルターを使用すると、そのクエリシェイプでクエリを再度有効にするまで、実行中中のクエリを拒否するようにMongoDBを構成できます。
つまり、低速クエリを特定したら、アプリケーションチームが低速クエリの影響を軽減するためにクエリを修正するのを待つ必要はありません。 代わりに、クエリプロファイラー、リアルタイム パフォーマンス パネル、またはクエリ ログのいずれかでクエリのパフォーマンスが低下していることに気付いたら、そのクエリシェイプに 拒否フィルター を設定できます。 その後、 MongoDBはその受信クエリシェイプの新しいインスタンスが実行されないようにします。 クエリを修正したら、クエリシェイプを再度有効にできます。
次の場合は、操作拒否フィルターを使用する必要があります。
修正の進行中に低速クエリの影響を迅速に排除します。
過負荷時は、重要でないクエリを拒否して、より重要なワークロードを優先します。
最大リソース使用率に近い場合は、クラスターに時間を与えて回復します。
Atlas UIでの低速クエリの識別と拒否
Atlas UIで操作拒否フィルターを使用するには、次の手順に従います。
Atlas Atlasで、プロジェクトの {0 ページにGoします。GoClusters
まだ表示されていない場合は、希望するプロジェクトを含む組織を選択しますナビゲーション バーのOrganizationsメニュー
まだ表示されていない場合は、ナビゲーション バーのProjectsメニューから目的のプロジェクトを選択します。
まだ表示されていない場合は、サイドバーの [Clusters] をクリックします。
[ Clusters (クラスター) ] ページが表示されます。
特定のクエリシェイプの操作を拒否します。
db.adminCommand()
関数でsetQuerySettings
を使用します。
拒否またはタイムアウト後にクエリを監視する
[ メトリクス] タブで、クエリがその後実行される方法を監視できます。
読み取り操作のクラスターレベルのタイムアウト
本番環境に到達する前に、開発プロセスでクエリの効率を慎重に検討することが重要です。 例外は常に発生する可能性がありますが、非効率的なクエリに対して先を見越して軽減することで、クラスターのパフォーマンスの問題を防ぐことができます。
MongoDB 8.0を使用すると、サーバー側のdefaultMaxTimeMS
がクラスターに取り込まれるインデックスなしの操作からクエリを保護できます。 操作がこのタイムアウトを超えると、 MongoDBは操作をキャンセルして、クエリが長時間実行中されすぎてリソースが保持されるのを防ぎます。 これにより、次のことが可能になります。
タイムアウトを設定する責任を、個々のアプリケーションチームからデータベースフォーカス チームに移行します。
クエリにインデックスがない場合のコレクションスキャンの影響を最小限に抑えます。
コストのかかる操作に対して最後のラウンドの軽減を用意することで、本番環境に移行します。
分析クエリなど、異なるタイムアウトを必要とするクエリがある場合は、 maxTimeMSメソッドで操作レベルのタイムアウトを設定することで、それらを上書きできます。
Atlas Administration APIで読み取り操作のデフォルト タイムアウトを設定する
Atlas Administration APIからdefaultMaxTimeMS
パラメータを設定するには、「 1 つのクラスターの高度な構成オプションを更新する 」を参照してください。
Atlas UIでの読み取り操作のデフォルト タイムアウトの設定
Atlas UIでdefaultMaxTimeMS
パラメータを設定するには、次の手順に従います。
設定オプションに移動します。
既存のクラスターがある場合は、[ クラスターの編集 ]ページに移動します。
新しいクラスターを作成している場合は、 Select a versionドロップダウンから [ MongoDB 8.0 ] を選択します。
[Additional Settings] をクリックします。
下にスクロールしてMore Configuration Options ] をクリックします。
強制終了された操作の動作を確認するには、「拒否またはタイムアウト後のクエリを監視する 」を参照してください。 詳しくは、「 defaultMaxTimeMS
と読み取り操作のデフォルト タイムアウトの設定 」を参照してください。
シャーディングされていないコレクションの影響を分離する
シャー増やすにより、クラスターを水平方向にスケーリングできます。 MongoDBを使用すると、一部のコレクションをシャーディングしながら、同じクラスター内の他のコレクションはシャーディングされないままにできます。 新しいデータベースを作成すると、クラスター内のデータ量が最も少ないシャードがデフォルトでそのデータベースのプライマリシャードとして選択されデフォルト。 そのデータベースのシャーディングされていないコレクションは、デフォルトでそのプライマリシャードに配置されます。 これにより、特にワークロードロードの増加がプライマリシャードのシャーディングされていないコレクションに集中する場合、ワークロードの増加に伴いプライマリシャードへのトラフィックが増加する可能性があります。
このワークロードをより分散するために、 MongoDB 8.0では、 moveCollection
コマンドを使用して、シャーディングされていないコレクションをプライマリシャードから他のシャードに移動できます。 これにより、アクティブで多目的なコレクションを、リソース使用量の少ないシャードに配置できます。 これを使用すると、次のことが可能になります。
大規模で複雑なワークロードのパフォーマンスを最適化します。
リソース使用率の向上を実現します。
シャード間で日付をより均等に分散します。
次の状況では、コレクションを分離することをお勧めします。
高スループットのシャーディングされていないコレクションが複数あるためにプライマリシャードに重大なワークロードが発生した場合。
シャーディングされていないコレクションでは将来、増加が予想され、他のコレクションのボトルネックになる可能性があります。
クラスターごとに 1 コレクションの配置設計を実行中していて、優先順位やワークロードに基づいてそれらのカスタマーを分離したいと考えています。
シャードには、シャーディングされていないコレクションの数が含まれているため、データ量が按分されています。
mongosh
を使用してシャーディングされていないコレクションを移動する方法については、「コレクションの移動 」を参照してください。
アプリケーションとクライアント側のベストプラクティス
MongoDB 配置とドライバー ライブラリの機能を構成して、ネットワーク停止やフェイルオーバー イベントに耐性のあるアプリケーションを作成できます。 MongoDB Atlas の 常時オン 機能を活用するアプリケーション コードを作成するには、次のタスクを実行する必要があります。
アプリケーション に適した
majority
の書込み保証 (write concern)と読み取り保証 (read concern)を使用しアプリケーション。アプリケーション内のエラーを処理します。
最新のドライバーのインストール
MongoDBドライバーからご使用の言語の最新ドライバーをインストールします。 ドライバーはアプリケーションからデータベースにクエリを接続して中継します。 最新のドライバーを使用すると、最新のMongoDB機能が有効になります。
次に、アプリケーションに依存関係をインポートします。
Maven を使用している場合 に、次のものをpom.xml
依存関係リストに追加します。
<dependencies> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongodb-driver-sync</artifactId> <version>4.0.1</version> </dependency> </dependencies>
Gradle を使用している場合は、次のものを build.gradle
依存関係リストに追加します。
dependencies { compile 'org.mongodb:mongodb-driver-sync:4.0.1' }
// Latest 'mongodb' version installed with npm const MongoClient = require('mongodb').MongoClient;
# Install the latest 'pymongo' version with pip and # import MongoClient from the package to establish a connection. from pymongo import MongoClient
接続文字列
注意
Atlasには、事前構成された接続文字列が用意されています。 事前構成された string をコピーする手順については、「 Atlas が提供する接続文字列 」を参照してください。
Atlas クラスター内のすべてのノードを指定する 接続文字列を使用して、アプリケーションをデータベースに接続します。クラスターでレプリカセットの選挙が実行され、新しいプライマリが選択された場合、クラスター内のすべてのノードを指定する接続文字列は、アプリケーション ロジックなしで新しいプライマリを検出します。
次のいずれかを使用して、クラスター内のすべてのノードを指定できます。
標準接続文字列形式、または
DNS シードリスト接続形式(Atlas で推奨)。
接続文字列では、オプション( retryWritesとwriteConcern など)を指定することもできます。
Atlas は、プライベート エンドポイント サービスのロード バランサーを使用して、シャーディングされたクラスター用に最適化された SRV 接続文字列を生成できます。最適化された接続文字列を使用する場合、Atlas はアプリケーションとシャーディングされたクラスター間の mongos
ごとの接続数を制限します。mongos
あたりの接続数を制限すると、接続数が急増した際のパフォーマンスが向上します。
プライベートエンドポイントの背後にあるシャーディングされたクラスターに最適化された接続文字列の詳細については、「プライベートエンドポイントの背後にあるシャーディングされたクラスターの接続パフォーマンスの向上」を参照してください。
Atlas が提供する接続文字列
Atlas クラスター インターフェースから接続文字列をコピーする場合、接続文字列 はクラスター用に事前構成され、DNS シードリスト形式を使用し、回復力のために推奨されるretryWrites
とw
(書込み保証(write concern))オプションが含まれます。
Atlas から接続文字列 URI をコピーするには、次の手順に従います。
AtlasGoClustersAtlas で、プロジェクトの ページにGoします。
まだ表示されていない場合は、希望するプロジェクトを含む組織を選択しますナビゲーション バーのOrganizationsメニュー
まだ表示されていない場合は、ナビゲーション バーのProjectsメニューから目的のプロジェクトを選択します。
まだ表示されていない場合は、サイドバーの [Clusters] をクリックします。
[ Clusters (クラスター) ] ページが表示されます。
接続文字列 URI をコピーします。
接続文字列またはドライバー全体のサンプルをアプリケーション コードにコピーします。 データベースユーザーの認証情報を提供する必要があります。
注意
このガイドでは、SCRAM 接続 に 認証string を使用します。X. 509証明書を使用して認証する方法については、 X. 509を参照してください。
接続文字列を使用して、アプリケーション内で MongoDB クライアントをインスタンス化します。
// Copy the connection string provided by Atlas String uri = <your Atlas connection string>; // Instantiate the MongoDB client with the URI MongoClient client = MongoClients.create(uri);
// Copy the connection string provided by Atlas const uri = <your Atlas connection string>; // Instantiate the MongoDB client with the URI const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
# Copy the connection string provided by Atlas uri = <your Atlas connection string> # Pass your connection string URI to the MongoClient constructor client = MongoClient(uri)
再試行可能な書込みと読み取り
注意
MongoDB バージョン4.0および4.2互換ドライバーを使用すると、MongoDB はデフォルトで書込みと読み取りの両方を 1 回再試行します。
再試行可能な書き込み
再試行可能な書込みを使用して、特定の書込み操作が失敗した場合に 1 回再試行します。 Atlas から接続文字列をコピーした場合は、"retryWrites=true"
が含まれます。独自の接続文字列を指定する場合は、クエリ パラメータとして "retryWrites=true"
を含めます。
書き込みを 1 回だけ 再試行する ことは、アプリケーションが正常な プライマリ ノード を一時的に見つけられない場合に、一時的なネットワークエラーやレプリカセットの選挙を処理するための最善の戦略です。 再試行が成功すると、操作全体が成功し、エラーは返されません。 操作が失敗した場合は、次の理由が原因で失敗した可能性があります。
永続的なネットワークエラー
無効なコマンド
操作が失敗した場合、アプリケーションは自分自身を処理する必要があります。
再試行可能な読み取り
MongoDB バージョン4.0および4.2互換ドライバーの使用に失敗した場合、読み取り操作は 1 回自動的に再試行されます。 読み取りを再試行するために追加の構成は必要ありません。
書込み保証 (write concern) と読み取り保証 (read concern)
書込み保証 (write concern) と読み取り保証 (read concern) を使用して、アプリケーションの整合性と可用性を調整できます。 懸念が深い場合は、データベース操作により強力なデータ整合性保証が必要になりますが、整合性要件を緩和すると可用性が向上します。
例
アプリケーションが金銭の残高を処理する場合、整合性は非常に重要です。 majority
の書込み保証と読み取り保証を使用して、古いデータやロールバックされる可能性のあるデータからの読み取りを行わないようにできます。
あるいは、アプリケーションが 1 秒ごとに数百のセンサーからの温度データを記録する場合、最新の読み取り値を含まないデータを読み取る場合は問題が発生しない場合があります。 整合性要件を緩和して、そのデータへのアクセスをより速くできます。
書込み保証 (write concern)
Atlas 接続文字列 URI を使用して、レプリカセットの 書込み保証レベルを設定できます。majority
書込み保証(write concern)を使用して、データがデータベースに正常に書き込まれ、永続化されるようにします。 これは推奨のデフォルトであり、ほとんどのユースケースで十分です。 Atlas から接続文字列をコピーした場合は、"w=majority"
が含まれます。
majority
など、確認応答が必要な書込み保証を使用する場合は、そのレベルの確認応答を実現するための書込みの最大時間制限を指定することもできます。
すべての書き込み (write) のwtimeoutMS接続文字列パラメータ、または
単一の書込み (write) 操作のwtimeoutオプション。
時間制限を使用するかどうかと使用する値は、アプリケーションのコンテキストによって異なります。
重要
書込み (write) に時間制限を指定せず、書込み保証 (write concern) レベルが達成できない場合、書込み (write) 操作は無期限にハングします。
読み取り保証(read concern)
Atlas 接続文字列 URI を使用して、 レプリカセットの 読み取り保証レベル を設定できます。理想的な読み取り保証はアプリケーションの要件によって異なりますが、ほとんどのユースケースではデフォルトで十分です。 デフォルトの読み取り保証を使用する場合、接続文字列パラメーターは必要ありません。
読み取り保証を指定すると、アプリケーションが Atlas から受信するデータの保証が強化されます。
注意
アプリケーションが使用する書込み保証 (write concern) と読み取り保証 (read concern) の特定の組み合わせは、操作順序の保証に影響します。 これは 因果整合性 と呼ばれます。 因果整合性の保証の詳細については、「因果整合性、読み取り保証、書込み保証 」を参照してください。
Error Handling
再試行可能な書き込みで処理されていないコマンド、ネットワークの停止、ネットワークエラーはエラーを返します。 エラーの詳細については、ドライバーのAPIドキュメントを参照してください。
たとえば、アプリケーションが、データベースの コレクションで既に使用されている_id
値を含むドキュメントを挿入しようとすると、ドライバーは次のようなエラーを返します。
Unable to insert due to an error: com.mongodb.MongoWriteException: E11000 duplicate key error collection: <db>.<collection> ...
{ "name": : "MongoError", "message": "E11000 duplicate key error collection on: <db>.<collection> ... ", ... }
pymongo.errors.DuplicateKeyError: E11000 duplicate key error collection: <db>.<collection> ...
適切なエラー処理を行わないと、エラーによってアプリケーションが再起動されるまでリクエストの処理がブロックされる可能性があります。
アプリケーションは、クラッシュしたり副作用のないエラーを処理する必要があります。 コレクションに重複する_id
を挿入するアプリケーションの以前の例では、そのアプリケーションは次のようにエラーを処理できます。
// Declare a logger instance from java.util.logging.Logger private static final Logger LOGGER = ... ... try { InsertOneResult result = collection.insertOne(new Document() .append("_id", 1) .append("body", "I'm a goofball trying to insert a duplicate _id")); // Everything is OK LOGGER.info("Inserted document id: " + result.getInsertedId()); // Refer to the API documentation for specific exceptions to catch } catch (MongoException me) { // Report the error LOGGER.severe("Failed due to an error: " + me); }
... collection.insertOne({ _id: 1, body: "I'm a goofball trying to insert a duplicate _id" }) .then(result => { response.sendStatus(200) // send "OK" message to the client }, err => { response.sendStatus(400); // send "Bad Request" message to the client });
... try: collection.insert_one({ "_id": 1, "body": "I'm a goofball trying to insert a duplicate _id" }) return {"message": "User successfully added!"} except pymongo.errors.DuplicateKeyError as e: print ("The insert operation failed:", e)
この例の挿入操作では、 _id
フィールドが一意である必要があるため、2 回目に呼び出されるときに「重複キー」エラーがスローされます。 エラーがキャッチされ、クライアントに通知され、アプリは実行を続行します。 しかし、挿入操作は失敗します。ユーザーに メッセージを表示するか、操作を再試行するか、または別の操作を実行するかは、ユーザーが決定する必要があります。
エラーは常にログに記録する必要があります。 これ以上の処理エラーを発生させる一般的な戦略は次のとおりです。
エラーを、エラー メッセージとともにクライアントに返します。 これは、エラーを解決できず、アクションが完了できないことをユーザーに通知する必要がある場合に適した戦略です。
バックアップ データベースに書き込みます。 これは、エラーを解決できないが、リクエスト データが失われるリスクを避けたい場合に適した戦略です。
操作を1 回のデフォルトの 再試行 を超えて再試行します。 これは、エラーの原因をプログラムで解決して再試行する場合に適した戦略です。
アプリケーションのコンテキストに最適な戦略を選択する必要があります。
例
重複キー エラーの例では、エラーをログに記録する必要がありますが、操作は成功しないため、再試行しないでください。 代わりに、フォールバック データベースに書き込みを行い、後でそのデータベースの内容を確認して、情報が失われることを確認することができます。 ユーザーは他に何もする必要がなく、データが記録されるため、クライアントにエラーメッセージを送信しないことを選択できます。
ネットワークエラーの計画
操作が無期限にハングし、アプリケーションが新しい操作を実行する際にブロックされる場合は、エラーを返すことが推奨されます。 maxTimeMSメソッドを使用して、個々の操作に時間制限を設定でき、その時間制限を超えた場合にアプリケーションが処理するエラーを返します。
各操作に設定する時間制限は、その操作のコンテキストによって異なります。
例
アプリケーションがinventory
コレクションから簡単な製品情報を読み取って表示する場合、これらの読み取り操作にかかる時間は 1 時間のみであることがかなり確実です。 クエリの実行時間が異常に長い場合は、ネットワークの問題が永続していることを示す適切なインジケーターです。 この操作でmaxTimeMS
を 5000、つまり 5 秒に設定すると、アプリケーションはネットワークの問題があることを確認するとすぐにフィードバックを受け取ることを意味します。
フェイルオーバーのテスト
カバレッジされたテスト の考えで 、Atlas は定期的なメンテナンスや特定の構成変更に対してレプリカセットの選挙を自動的に実行します。
アプリケーションがレプリカセットの選挙に対して回復力があるかどうかを確認するには、フェイルオーバー イベントをシミュレートしてフェイルオーバー プロセスをテストします。
回復力のあるサンプルアプリケーション
サンプルアプリケーションには、ネットワーク停止やフェイルオーバー イベントに対する回復力を確保するために、次の推奨事項をまとめています。
Atlas が提供する接続文字列を、再試行可能な書き込み、過半数の書込み保証(write concern)、デフォルトの読み取り保証(read concern)とともに使用します。
optimemaxTimeMS メソッドを使用して 制限を指定します。
maxTimeMS
を設定する方法については、特定のドライバーのドキュメント を参照してください。重複キーとタイムアウトのエラーを処理します。
アプリケーションは、クライアントがユーザー レコードを作成または一覧表示できる HTTP APIです。 これにより、GET および POST リクエストを受け入れるエンドポイントが公開されます http://localhost:3000 :
方式 | エンドポイント | 説明 |
---|---|---|
|
|
|
|
| リクエスト本文に |
注意
次のサーバー アプリケーションは NaHTTPD を使用します および 実行前に、プロジェクトに 依存関係JSON として追加する必要があります。
1 // File: App.java 2 3 import java.util.Map; 4 import java.util.logging.Logger; 5 6 import org.bson.Document; 7 import org.json.JSONArray; 8 9 import com.mongodb.MongoException; 10 import com.mongodb.client.MongoClient; 11 import com.mongodb.client.MongoClients; 12 import com.mongodb.client.MongoCollection; 13 import com.mongodb.client.MongoDatabase; 14 15 import fi.iki.elonen.NanoHTTPD; 16 17 public class App extends NanoHTTPD { 18 private static final Logger LOGGER = Logger.getLogger(App.class.getName()); 19 20 static int port = 3000; 21 static MongoClient client = null; 22 23 public App() throws Exception { 24 super(port); 25 26 // Replace the uri string with your MongoDB deployment's connection string 27 String uri = "<atlas-connection-string>"; 28 client = MongoClients.create(uri); 29 30 start(NanoHTTPD.SOCKET_READ_TIMEOUT, false); 31 LOGGER.info("\nStarted the server: http://localhost:" + port + "/ \n"); 32 } 33 34 public static void main(String[] args) { 35 try { 36 new App(); 37 } catch (Exception e) { 38 LOGGER.severe("Couldn't start server:\n" + e); 39 } 40 } 41 42 43 public Response serve(IHTTPSession session) { 44 StringBuilder msg = new StringBuilder(); 45 Map<String, String> params = session.getParms(); 46 47 Method reqMethod = session.getMethod(); 48 String uri = session.getUri(); 49 50 if (Method.GET == reqMethod) { 51 if (uri.equals("/")) { 52 msg.append("Welcome to my API!"); 53 } else if (uri.equals("/users")) { 54 msg.append(listUsers(client)); 55 } else { 56 msg.append("Unrecognized URI: ").append(uri); 57 } 58 } else if (Method.POST == reqMethod) { 59 try { 60 String name = params.get("name"); 61 if (name == null) { 62 throw new Exception("Unable to process POST request: 'name' parameter required"); 63 } else { 64 insertUser(client, name); 65 msg.append("User successfully added!"); 66 } 67 } catch (Exception e) { 68 msg.append(e); 69 } 70 } 71 72 return newFixedLengthResponse(msg.toString()); 73 } 74 75 static String listUsers(MongoClient client) { 76 MongoDatabase database = client.getDatabase("test"); 77 MongoCollection<Document> collection = database.getCollection("users"); 78 79 final JSONArray jsonResults = new JSONArray(); 80 collection.find().forEach((result) -> jsonResults.put(result.toJson())); 81 82 return jsonResults.toString(); 83 } 84 85 static String insertUser(MongoClient client, String name) throws MongoException { 86 MongoDatabase database = client.getDatabase("test"); 87 MongoCollection<Document> collection = database.getCollection("users"); 88 89 collection.insertOne(new Document().append("name", name)); 90 return "Successfully inserted user: " + name; 91 } 92 }
注意
次のサーバー アプリケーションは Express を使用します は、実行前にプロジェクトに依存関係として追加する必要があります。
1 const express = require('express'); 2 const bodyParser = require('body-parser'); 3 4 // Use the latest drivers by installing & importing them 5 const MongoClient = require('mongodb').MongoClient; 6 7 const app = express(); 8 app.use(bodyParser.json()); 9 app.use(bodyParser.urlencoded({ extended: true })); 10 11 const uri = "mongodb+srv://<db_username>:<db_password>@cluster0-111xx.mongodb.net/test?retryWrites=true&w=majority"; 12 13 const client = new MongoClient(uri, { 14 useNewUrlParser: true, 15 useUnifiedTopology: true 16 }); 17 18 // ----- API routes ----- // 19 app.get('/', (req, res) => res.send('Welcome to my API!')); 20 21 app.get('/users', (req, res) => { 22 const collection = client.db("test").collection("users"); 23 24 collection 25 .find({}) 26 .maxTimeMS(5000) 27 .toArray((err, data) => { 28 if (err) { 29 res.send("The request has timed out. Please check your connection and try again."); 30 } 31 return res.json(data); 32 }); 33 }); 34 35 app.post('/users', (req, res) => { 36 const collection = client.db("test").collection("users"); 37 collection.insertOne({ name: req.body.name }) 38 .then(result => { 39 res.send("User successfully added!"); 40 }, err => { 41 res.send("An application error has occurred. Please try again."); 42 }) 43 }); 44 // ----- End of API routes ----- // 45 46 app.listen(3000, () => { 47 console.log(`Listening on port 3000.`); 48 client.connect(err => { 49 if (err) { 50 console.log("Not connected: ", err); 51 process.exit(0); 52 } 53 console.log('Connected.'); 54 }); 55 });
注意
次のウェブ アプリケーションは FastAPI を使用します 。新しいアプリケーションを作成するには、 FastAPI サンプル ファイル を使用します 構造体。
1 # File: main.py 2 3 from fastapi import FastAPI, Body, Request, Response, HTTPException, status 4 from fastapi.encoders import jsonable_encoder 5 6 from typing import List 7 from models import User 8 9 import pymongo 10 from pymongo import MongoClient 11 from pymongo import errors 12 13 # Replace the uri string with your |service| connection string 14 uri = "<atlas-connection-string>" 15 db = "test" 16 17 app = FastAPI() 18 19 20 def startup_db_client(): 21 app.mongodb_client = MongoClient(uri) 22 app.database = app.mongodb_client[db] 23 24 25 def shutdown_db_client(): 26 app.mongodb_client.close() 27 28 ##### API ROUTES ##### 29 30 def list_users(request: Request): 31 try: 32 users = list(request.app.database["users"].find().max_time_ms(5000)) 33 return users 34 except pymongo.errors.ExecutionTimeout: 35 raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="The request has timed out. Please check your connection and try again.") 36 37 38 def new_user(request: Request, user: User = Body(...)): 39 user = jsonable_encoder(user) 40 try: 41 new_user = request.app.database["users"].insert_one(user) 42 return {"message":"User successfully added!"} 43 except pymongo.errors.DuplicateKeyError: 44 raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Could not create user due to existing '_id' value in the collection. Try again with a different '_id' value.")