MongoDB エラーの処理

MongoDBBeginner
オンラインで実践に進む

はじめに

この実験では、MongoDB で一般的なエラーを処理するための必須テクニックを学びます。MongoDB Shell (mongosh) を使用して、接続障害、重複キーエラー、データ検証エラーなど、さまざまな問題を特定し、解決する練習を行います。この実験の終わりには、データベース操作をより信頼性が高く堅牢にする方法についての実践的な理解が得られるでしょう。

MongoDB への接続とエラー処理

データベースを扱う上で、接続エラーはよくある問題です。サーバーアドレスの間違い、ネットワークの問題、データベースサーバーが実行されていないなど、さまざまな原因で発生する可能性があります。このステップでは、接続エラーを特定し、その後正常に接続する方法を学びます。

まず、MongoDB が実行されていないポートに接続を試みます。MongoDB のデフォルトポートは 27017 です。ここではポート 27018 に接続を試みます。

ターミナルで以下のコマンドを実行してください。

mongosh "mongodb://localhost:27018"

このコマンドは、指定されたアドレスに MongoDB サーバーが見つからないため失敗し、エラーが返されます。出力は以下のようになります。

MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27018

MongoNetworkError は、接続の失敗を明確に示しています。ECONNREFUSED の部分は、ターゲットマシンが接続を積極的に拒否したことを示しており、通常はポートでサービスがリッスンしていないことを意味します。

次に、正しいポートに接続しましょう。MongoDB サービスは、セットアップフェーズ中に起動されています。それに接続するには、引数なしで mongosh コマンドを実行します。これにより、デフォルトの接続文字列 mongodb://127.0.0.1:27017 が使用されます。

mongosh

接続が成功すると、ようこそメッセージと test> プロンプトが表示され、デフォルトの test データベースに接続されていることが示されます。

Current Mongosh Log ID: ...
Connecting to:          mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.2.6
Using MongoDB:          8.0.0
Using Mongosh:          2.2.6
...
test>

これで MongoDB サーバーに接続されました。次のステップのために、このターミナルを開いたまま mongosh シェル内に留まってください。

重複キーエラーの処理

データ整合性の維持は、あらゆるアプリケーションにとって非常に重要です。データ整合性に関する最も一般的な問題の 1 つは、レコードの重複です。MongoDB は、インデックス付けされたフィールドが重複した値を格納しないことを保証するユニークインデックスを通じて、これを防止します。

前のステップから mongosh シェルに入っているはずです。まず、errorlab という名前の新しいデータベースに切り替えます。データベースは、最初にデータを格納したときに自動的に作成されます。

use errorlab

次に、新しい users コレクションの email フィールドにユニークインデックスを作成します。このコマンドは、users コレクション内のすべてのドキュメントが email フィールドに対してユニークな値を持つ必要があることを MongoDB に伝えます。

db.users.createIndex({ email: 1 }, { unique: true });

出力は、インデックスが正常に作成されたことを確認します。

{
  "numIndexesBefore": 1,
  "numIndexesAfter": 2,
  "createdCollectionAutomatically": true,
  "ok": 1
}

次に、ドキュメントを users コレクションに挿入します。コレクションは空で、メールアドレスもユニークであるため、この操作は成功します。

db.users.insertOne({ name: "John Doe", email: "john@example.com" });

挿入されたドキュメントの ID を含む確認メッセージが表示されます。

{
  "acknowledged": true,
  "insertedId": ObjectId("...")
}

次に、まったく同じメールアドレスを持つ別のドキュメントを挿入しようとします。

db.users.insertOne({ name: "Jane Doe", email: "john@example.com" });

今回は、操作が失敗します。MongoDB は、重複キーエラーを示す特定の error code E11000 を持つ MongoBulkWriteError を返します。これは、データ整合性を保護するための期待される動作です。

MongoServerError: E11000 duplicate key error collection: errorlab.users index: email_1 dup key: { email: "john@example.com" }

Upsert による重複キーの解決

重複を防止することは重要ですが、場合によっては、レコードが存在する場合は更新し、存在しない場合は作成したいことがあります。この「更新または挿入」のロジックは、一般的な要件です。MongoDB は、upsert オプションを使用して、これをクリーンに処理する方法を提供します。

john@example.com というメールアドレスを持つユーザーを更新してみましょう。updateOne メソッドを使用し、upsert オプションを true に設定します。

db.users.updateOne(
  { email: "john@example.com" },
  { $set: { name: "John Doe Updated", lastUpdated: new Date() } },
  { upsert: true }
);

出力は、1 つのドキュメントが一致し、変更されたことを示しています。既存のドキュメントが更新され、新しいドキュメントが挿入されたわけではないため、upsertedIdnull です。

{
  "acknowledged": true,
  "matchedCount": 1,
  "modifiedCount": 1,
  "upsertedId": null
}

次に、まだ存在しないユーザー jane@example.com に対して同様のコマンドを実行します。

db.users.updateOne(
  { email: "jane@example.com" },
  { $set: { name: "Jane Doe", lastUpdated: new Date() } },
  { upsert: true }
);

今回は、出力は matchedCount が 0 であることを示していますが、upsertedId で示されるように、新しいドキュメントが作成されました。

{
  "acknowledged": true,
  "matchedCount": 0,
  "modifiedCount": 0,
  "upsertedId": ObjectId("...")
}

結果を確認するには、コレクションをクエリしてすべてのドキュメントを表示できます。pretty() メソッドは、出力を読みやすくフォーマットします。

db.users.find().pretty();

出力には、John の更新された名前を持つドキュメントと、Jane の新しく作成されたドキュメントの両方が表示されます。upsert オプションは、「作成または更新」シナリオを処理するための強力でアトミックな方法を提供します。

クエリおよびバリデーションエラーの処理

データをクエリする際や、挿入されたデータが定義済みのルールに準拠しない場合にもエラーが発生する可能性があります。このステップでは、クエリ構文エラーとデータバリデーションエラーについて説明します。

まず、存在しないクエリ演算子を使用した場合に何が起こるかを見てみましょう。これは一般的なタイプミスです。

db.users.find({ name: { $invalidOperator: "John" } });

MongoDB は $invalidOperator を認識しないため、すぐにエラーを返します。

MongoServerError[BadValue]: unknown operator: $invalidOperator

次に、より強力な機能であるスキーマバリデーションについて説明します。ドキュメントがコレクションに挿入または更新される際に従う必要があるルールを定義できます。ここでは、name (文字列) と price (数値) を必須とするバリデーターを持つ新しい products コレクションを作成します。

db.createCollection("products", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["name", "price"],
      properties: {
        name: {
          bsonType: "string",
          description: "must be a string and is required"
        },
        price: {
          bsonType: "number",
          description: "must be a number and is required"
        }
      }
    }
  }
});

次に、price を数値ではなく文字列として提供することで、このスキーマに違反するドキュメントを挿入しようとします。

db.products.insertOne({ name: "Laptop", price: "1200" });

操作は MongoBulkWriteError で失敗します。Document failed validation というメッセージが理由を明確に示しており、不正なデータがデータベースに入るのを防ぎます。

MongoServerError: Document failed validation
...

最後に、スキーマに準拠した有効なドキュメントを挿入します。

db.products.insertOne({ name: "Laptop", price: 1200 });

ドキュメントが有効であるため、この操作は成功します。

{
  "acknowledged": true,
  "insertedId": ObjectId("...")
}

スキーマバリデーションは、データベース内で直接データの一貫性を強制するための強力なツールです。

まとめ

この実験では、mongosh シェルを使用して、MongoDB の一般的なエラータイプをいくつか処理する方法を学びました。まず、接続エラーを特定して解決しました。次に、重複キーエラーを防ぐためにユニークインデックスを作成して、データの整合性を強制しました。「更新または挿入」ロジックを適切に処理するために upsert オプションの使用方法も学びました。最後に、クエリ構文エラーを調査し、スキーマバリデーションを使用して無効なデータがデータベースに保存されるのを防ぎました。これらの基本的なエラー処理スキルは、MongoDB で信頼性が高く堅牢なアプリケーションを構築するために不可欠です。