開発者ドキュメント

MongoDBでスキーマ検証を使用する方法

序章

リレーショナルデータベースの重要な側面の1つは、データベースを行と列で構成されるテーブルに格納することです。これらは、既知のデータ型のフィールドを持つ固定された厳密なスキーマで動作します。 MongoDBのようなドキュメント指向データベースは、必要に応じてドキュメントの構造を再形成できるため、この点でより柔軟性があります。

ただし、特定の構造に従うか、特定の要件を満たすためにデータドキュメントが必要になる場合があります。 多くのドキュメントデータベースでは、ドキュメントのデータの一部をどのように構造化するかを指示するルールを定義できますが、必要に応じてこの構造を自由に変更できます。

MongoDBには、ドキュメントの構造に制約を適用できるスキーマ検証と呼ばれる機能があります。 スキーマ検証は、JSONドキュメント構造の記述と検証のオープンスタンダードである JSONSchemaを中心に構築されています。 このチュートリアルでは、検証ルールを記述して適用し、MongoDBコレクションの例でドキュメントの構造を制御します。

前提条件

このチュートリアルに従うには、次のものが必要です。

注:サーバーの構成方法、MongoDBのインストール方法、およびMongoDBのインストールを保護する方法に関するリンクされたチュートリアルは、Ubuntu20.04を参照しています。 このチュートリアルは、基盤となるオペレーティングシステムではなく、MongoDB自体に焦点を当てています。 通常、認証が有効になっている限り、オペレーティングシステムに関係なく、すべてのMongoDBインストールで機能します。

ステップ1—スキーマ検証を適用せずにドキュメントを挿入する

MongoDBのスキーマ検証機能とそれらが役立つ理由を強調するために、このステップでは、MongoDBシェルを開いて、ローカルにインストールされたMongoDBインスタンスに接続し、その中にサンプルコレクションを作成する方法の概要を説明します。 次に、このコレクションにいくつかのサンプルドキュメントを挿入することで、このステップでは、MongoDBがデフォルトでスキーマ検証を強制しない方法を示します。 後の手順で、このようなルールの作成と適用を自分で開始します。

このガイドで使用するサンプルコレクションを作成するには、管理ユーザーとしてMongoDBシェルに接続します。 このチュートリアルは、前提条件 MongoDBセキュリティチュートリアルの規則に従い、この管理ユーザーの名前が AdminSammy であり、その認証データベースが admin. 異なる場合は、次のコマンドでこれらの詳細を変更して、独自の設定を反映させてください。

  1. mongo -u AdminSammy -p --authenticationDatabase admin

インストール中に設定したパスワードを入力して、シェルにアクセスします。 パスワードを入力すると、 > プロンプトサイン。

スキーマ検証機能を説明するために、このガイドの例では、世界で最も高い山を表すドキュメントを含むサンプルデータベースを使用しています。 エベレストのサンプルドキュメントは次の形式になります。

エベレスト文書
{
    "name": "Everest",
    "height": 8848,
    "location": ["Nepal", "China"],
    "ascents": {
        "first": {
            "year": 1953,
        },
        "first_winter": {
            "year": 1980,
        },
        "total": 5656,
    }
}

このドキュメントには、次の情報が含まれています。

次を実行します insertOne() 名前の付いたコレクションを同時に作成するメソッド peaks MongoDBインストールで、エベレストを表す前のサンプルドキュメントを挿入します。

  1. db.peaks.insertOne(
  2. {
  3. "name": "Everest",
  4. "height": 8848,
  5. "location": ["Nepal", "China"],
  6. "ascents": {
  7. "first": {
  8. "year": 1953
  9. },
  10. "first_winter": {
  11. "year": 1980
  12. },
  13. "total": 5656
  14. }
  15. }
  16. )

出力には、成功メッセージと、新しく挿入されたオブジェクトに割り当てられたオブジェクト識別子が含まれます。

Output
{ "acknowledged" : true, "insertedId" : ObjectId("618ffa70bfa69c93a8980443") }

提供されたを実行してこのドキュメントを挿入しましたが insertOne() この方法では、このドキュメントの構造を完全に自由に設計できます。 場合によっては、データベース内のドキュメントの構造にある程度の柔軟性が必要になることがあります。 ただし、データの分析や処理を容易にするために、ドキュメントの構造の一部の側面に一貫性を持たせることもできます。

これが重要である理由を説明するために、このデータベースに入力される可能性のある他のいくつかのサンプルドキュメントを検討してください。

次のドキュメントは、エベレストを表す前のドキュメントとほぼ同じですが、 name 分野:

名前のない山
{
    "height": 8611,
    "location": ["Pakistan", "China"],
    "ascents": {
        "first": {
            "year": 1954
        },
        "first_winter": {
            "year": 1921
        },
        "total": 306
    }
}

世界で最も高い山のリストを含むデータベースの場合、山を表すがその名前を含まないドキュメントを追加すると、重大なエラーになる可能性があります。

この次のサンプルドキュメントでは、山の名前が表示されていますが、山の高さは数字ではなく文字列として表されています。 さらに、場所は配列ではなく単一の値であり、上昇の試行の総数に関する情報はありません。

高さの文字列値を持つ山
{
    "name": "Manaslu",
    "height": "8163m",
    "location": "Nepal"
}

この例と同じくらい多くの省略があるドキュメントを解釈することは難しいかもしれません。 たとえば、次の場合、コレクションをピーク高さで正常に並べ替えることはできません。 height 属性値は、ドキュメント間で異なるデータ型として保存されます。

次に、以下を実行します insertMany() これらのドキュメントをエラーを発生させずにデータベースに挿入できるかどうかをテストする方法:

  1. db.peaks.insertMany([
  2. {
  3. "height": 8611,
  4. "location": ["Pakistan", "China"],
  5. "ascents": {
  6. "first": {
  7. "year": 1954
  8. },
  9. "first_winter": {
  10. "year": 1921
  11. },
  12. "total": 306
  13. }
  14. },
  15. {
  16. "name": "Manaslu",
  17. "height": "8163m",
  18. "location": "Nepal"
  19. }
  20. ])

結局のところ、MongoDBはエラーを返さず、両方のドキュメントが正常に挿入されます。

Output
{ "acknowledged" : true, "insertedIds" : [ ObjectId("618ffd0bbfa69c93a8980444"), ObjectId("618ffd0bbfa69c93a8980445") ] }

この出力が示すように、これらのドキュメントは両方とも有効なJSONであり、コレクションに挿入するのに十分です。 ただし、これだけではデータベースの論理的な一貫性と意味を維持するのに十分ではありません。 次の手順では、スキーマ検証ルールを作成して、 peaks コレクションは、いくつかの重要な要件に従います。

ステップ2—文字列フィールドの検証

MongoDBでは、スキーマ検証は、JSONスキーマドキュメントをコレクションに割り当てることで個々のコレクションに対して機能します。 JSON Schema は、JSONドキュメントの構造を定義および検証できるオープンスタンダードです。 これを行うには、特定のコレクション内のドキュメントが有効であると見なされるために従わなければならない一連の要件をリストするスキーマ定義を作成します。

特定のコレクションは単一のJSONスキーマのみを使用できますが、コレクションの作成時またはその後いつでもスキーマを割り当てることができます。 後で元の検証ルールを変更する場合は、元のJSONスキーマドキュメントを新しい要件に一致するものに置き換える必要があります。

JSONスキーマバリデータードキュメントをに割り当てるには peaks 前の手順で作成したコレクションの場合、次のコマンドを実行できます。

  1. db.runCommand({
  2. "collMod": "collection_name",
  3. "validator": {
  4. $jsonSchema: {JSON_Schema_document}
  5. }
  6. })

The runCommand メソッドはを実行します collMod コマンド。これは、を適用して指定されたコレクションを変更します。 validator それに属性します。 The validator 属性はスキーマ検証を担当し、この構文例では、属性は $jsonSchema オペレーター。 この演算子は、特定のコレクションのスキーマバリデーターとして使用されるJSONスキーマドキュメントを定義します。

警告:実行するために collMod コマンドを実行するには、MongoDBユーザーに適切な権限を付与する必要があります。 Ubuntu 20.04 でMongoDBを保護する方法の前提条件のチュートリアルに従い、そのガイドで作成した管理ユーザーとしてMongoDBインスタンスに接続している場合は、それに続く追加の役割を付与する必要があります。このガイドの例。

まず、ユーザーの認証データベースに切り替えます。 これは admin 次の例では、異なる場合は自分のユーザーの認証データベースに接続します。

  1. use admin
Output
switched to db admin

次に、 grantRolesToUser() メソッドを使用して、ユーザーに dbAdmin 作成したデータベースに対する役割 peaks コレクション。 次の例では、 peaks コレクションは test データベース:

  1. db.grantRolesToUser(
  2. "AdminSammy",
  3. [ { role : "dbAdmin", db : "test" } ]
  4. )

または、ユーザーに dbAdminAnyDatabase 役割。 この役割の名前が示すように、それはあなたのユーザーに与えます dbAdmin MongoDBインスタンス上のすべてのデータベースに対する特権:

  1. db.grantRolesToUser(
  2. "AdminSammy",
  3. [ "dbAdminAnyDatabase" ]
  4. )

ユーザーに適切な役割を付与した後、データベースに戻って peaks コレクションが保存されます:

  1. use test
Output
switched to db test

コレクションを作成するときに、JSONスキーマバリデーターを割り当てることもできることに注意してください。 これを行うには、次の構文を使用できます。

  1. db.createCollection(
  2. "collection_name", {
  3. "validator": {
  4. $jsonSchema: {JSON_Schema_document}
  5. }
  6. })

前の例とは異なり、この構文には collMod これは、コレクションがまだ存在していないため、変更できないためです。 ただし、前の例と同様に、 collection_name バリデータードキュメントを割り当てるコレクションの名前であり、 validator オプションは、指定されたJSONスキーマドキュメントをコレクションのバリデーターとして割り当てます。

このように最初からJSONスキーマバリデーターを適用するということは、コレクションに追加するすべてのドキュメントがバリデーターによって設定された要件を満たさなければならないことを意味します。 ただし、既存のコレクションに検証ルールを追加すると、それらを変更しようとするまで、新しいルールは既存のドキュメントに影響を与えません。

に渡すJSONスキーマドキュメント validator 属性は、コレクションに適用するすべての検証ルールの概要を示す必要があります。 次のJSONスキーマの例では、 name フィールドはコレクション内のすべてのドキュメントに存在し、 name フィールドの値は常に文字列です。

名前フィールドを検証する最初のJSONスキーマドキュメント
{
    "bsonType": "object",
    "description": "Document describing a mountain peak",
    "required": ["name"],
    "properties": {
        "name": {
            "bsonType": "string",
            "description": "Name must be a string and is required"
        }
    },
}

このスキーマドキュメントは、コレクションに入力されたドキュメントの特定の部分が従わなければならない特定の要件の概要を示しています。 JSONスキーマドキュメントのルート部分(前のフィールド properties、この場合は bsonType, description、 と required)データベースドキュメント自体を記述します。

The bsonType プロパティは、検証エンジンが検出することを期待するデータ型を記述します。 データベースドキュメント自体の場合、予想されるタイプは次のとおりです。 object. これは、オブジェクトのみを追加できることを意味します。つまり、中括弧で囲まれた完全で有効なJSONドキュメント({})—このコレクションへ。 他の種類のデータ型(スタンドアロンの文字列、整数、配列など)を挿入しようとすると、エラーが発生します。

MongoDBでは、すべてのドキュメントがオブジェクトです。 ただし、JSONスキーマは、あらゆる種類の有効なJSONドキュメントを記述および検証するために使用される標準であり、プレーン配列または文字列も有効なJSONです。 MongoDBスキーマ検証を使用する場合、常にルートドキュメントを設定する必要があることがわかります。 bsonType としての値 object JSONスキーマバリデーターで。

次に、 description プロパティは、このコレクションで見つかったドキュメントの簡単な説明を提供します。 このフィールドは必須ではありませんが、ドキュメントの検証に使用されるだけでなく、JSONスキーマを使用してドキュメントの構造に注釈を付けることもできます。 これは、他のユーザーがドキュメントの目的を理解するのに役立ちます。 description フィールドは良い習慣になり得ます。

検証ドキュメントの次のプロパティは required 分野。 The required fieldは、コレクション内のすべてのドキュメントに存在する必要があるドキュメントフィールドのリストを含む配列のみを受け入れることができます。 この例では、 ["name"] これは、ドキュメントに含まれている必要があるのは name 有効と見なされるフィールド。

続いて properties ドキュメントフィールドの検証に使用されるルールを説明するオブジェクト。 ルールを定義するフィールドごとに、フィールドにちなんで名付けられた埋め込みJSONスキーマドキュメントを含めます。 にリストされていないフィールドのスキーマルールを定義できることに注意してください。 required 配列。 これは、データに必須ではないフィールドが含まれているが、それらが存在する場合でも特定のルールに従うようにしたい場合に役立ちます。

これらの埋め込みスキーマドキュメントは、メインドキュメントと同様の構文に従います。 この例では、 bsonType プロパティには、すべてのドキュメントが必要です name フィールドになる string. この埋め込みドキュメントには、簡単な説明も含まれています description 分野。

このJSONスキーマをに適用するには peaks 前の手順で作成したコレクションは、次を実行します runCommand() 方法:

  1. db.runCommand({
  2. "collMod": "peaks",
  3. "validator": {
  4. $jsonSchema: {
  5. "bsonType": "object",
  6. "description": "Document describing a mountain peak",
  7. "required": ["name"],
  8. "properties": {
  9. "name": {
  10. "bsonType": "string",
  11. "description": "Name must be a string and is required"
  12. }
  13. },
  14. }
  15. }
  16. })

MongoDBは、コレクションが正常に変更されたことを示す成功メッセージで応答します。

Output
{ "ok" : 1 }

その後、MongoDBではドキュメントをに挿入できなくなります peaks 彼らが持っていない場合はコレクション name 分野。 これをテストするには、前の手順で挿入した、山を完全に説明しているドキュメントを挿入してみてください。 name 分野:

  1. db.peaks.insertOne(
  2. {
  3. "height": 8611,
  4. "location": ["Pakistan", "China"],
  5. "ascents": {
  6. "first": {
  7. "year": 1954
  8. },
  9. "first_winter": {
  10. "year": 1921
  11. },
  12. "total": 306
  13. }
  14. }
  15. )

今回の操作では、ドキュメントの検証に失敗したことを示すエラーメッセージが表示されます。

Output
WriteError({ "index" : 0, "code" : 121, "errmsg" : "Document failed validation", . . . })

MongoDBは、JSONスキーマで指定された検証ルールに合格しなかったドキュメントを挿入しません。

注: MongoDB 5.0以降、検証が失敗すると、エラーメッセージは失敗した制約を示します。 MongoDB 4.4以前では、データベースは失敗の理由に関する詳細を提供しません。

次のコマンドを実行して、MongoDBがJSONスキーマに含めたデータ型の要件を適用するかどうかをテストすることもできます。 insertOne() 方法。 これは前回の操作と似ていますが、今回は name 分野。 ただし、このフィールドの値は文字列ではなく数値です。

  1. db.peaks.insertOne(
  2. {
  3. "name": 123,
  4. "height": 8611,
  5. "location": ["Pakistan", "China"],
  6. "ascents": {
  7. "first": {
  8. "year": 1954
  9. },
  10. "first_winter": {
  11. "year": 1921
  12. },
  13. "total": 306
  14. }
  15. }
  16. )

もう一度、検証は失敗します。 にもかかわらず name フィールドが存在しますが、文字列である必要があるという制約を満たしていません。

Output
WriteError({ "index" : 0, "code" : 121, "errmsg" : "Document failed validation", . . . })

もう一度試してくださいが、 name ドキュメントに存在し、その後に文字列値が続くフィールド。 今回、 name ドキュメント内の唯一のフィールドです:

  1. db.peaks.insertOne(
  2. {
  3. "name": "K2"
  4. }
  5. )

操作は成功し、ドキュメントは通常どおりオブジェクト識別子を受け取ります。

Output
{ "acknowledged" : true, "insertedId" : ObjectId("61900965bfa69c93a8980447") }

スキーマ検証ルールは、 name 分野。 この時点で、 name フィールドが検証要件を満たしている場合、ドキュメントはエラーなしで挿入されます。 ドキュメントの残りの部分は、任意の形をとることができます。

これで、最初のJSONスキーマドキュメントを作成し、最初のスキーマ検証ルールをに適用しました。 name フィールド、それが存在し、文字列である必要があります。 ただし、データ型ごとに異なる検証オプションがあります。 次に、各ドキュメントに保存されている数値を検証します height 分野。

ステップ3—数値フィールドの検証

次のドキュメントをに挿入したときに、手順1を思い出してください。 peaks コレクション:

高さの文字列値を持つ山
{
    "name": "Manaslu",
    "height": "8163m",
    "location": "Nepal"
}

このドキュメントは height 値は数値ではなく文字列であり、 insertMany() このドキュメントを挿入するために使用したメソッドは成功しました。 これが可能だったのは、の検証ルールをまだ追加していないためです。 height 分野。

挿入されたドキュメントが有効なJSON構文で記述されている限り、MongoDBは、このフィールドの任意の値(負の値など、このフィールドに意味をなさない値も含む)を受け入れます。 これを回避するには、前の手順のスキーマ検証ドキュメントを拡張して、 height 分野。

確認することから始めます height フィールドは、新しく挿入されたドキュメントに常に存在し、常に数値として表されます。 次のコマンドを使用して、スキーマ検証を変更します。

  1. db.runCommand({
  2. "collMod": "peaks",
  3. "validator": {
  4. $jsonSchema: {
  5. "bsonType": "object",
  6. "description": "Document describing a mountain peak",
  7. "required": ["name", "height"],
  8. "properties": {
  9. "name": {
  10. "bsonType": "string",
  11. "description": "Name must be a string and is required"
  12. },
  13. "height": {
  14. "bsonType": "number",
  15. "description": "Height must be a number and is required"
  16. }
  17. },
  18. }
  19. }
  20. })

このコマンドのスキーマドキュメントでは、 height フィールドはに含まれています required 配列。 同様に、 height 内のドキュメント properties 新しいものを必要とするオブジェクト height である値 number. 繰り返しますが、 description フィールドは補助的なものであり、含める説明は、他のユーザーがJSONスキーマの背後にある意図を理解できるようにするためだけのものにする必要があります。

MongoDBは、コレクションが正常に変更されたことを通知する短い成功メッセージで応答します。

Output
{ "ok" : 1 }

これで、新しいルールをテストできます。 検証ドキュメントに合格するために必要な最小限のドキュメント構造でドキュメントを挿入してみてください。 次のメソッドは、2つの必須フィールドのみを含むドキュメントを挿入します。 nameheight:

  1. db.peaks.insertOne(
  2. {
  3. "name": "Test peak",
  4. "height": 8300
  5. }
  6. )

挿入は成功します:

Output
{ acknowledged: true, insertedId: ObjectId("61e0c8c376b24e08f998e371") }

次に、不足しているドキュメントを挿入してみます height 分野:

  1. db.peaks.insertOne(
  2. {
  3. "name": "Test peak"
  4. }
  5. )

次に、を含む別のものを試してください height フィールドですが、このフィールドには文字列値が含まれています。

  1. db.peaks.insertOne(
  2. {
  3. "name": "Test peak",
  4. "height": "8300m"
  5. }
  6. )

どちらの場合も、操作によってエラーメッセージが表示され、失敗します。

Output
WriteError({ "index" : 0, "code" : 121, "errmsg" : "Document failed validation", . . . })

ただし、負の高さの山頂を挿入しようとすると、山は適切に保存されます。

  1. db.peaks.insertOne(
  2. {
  3. "name": "Test peak",
  4. "height": -100
  5. }
  6. )

これを防ぐために、スキーマ検証ドキュメントにさらにいくつかのプロパティを追加できます。 次の操作を実行して、現在のスキーマ検証設定を置き換えます。

  1. db.runCommand({
  2. "collMod": "peaks",
  3. "validator": {
  4. $jsonSchema: {
  5. "bsonType": "object",
  6. "description": "Document describing a mountain peak",
  7. "required": ["name", "height"],
  8. "properties": {
  9. "name": {
  10. "bsonType": "string",
  11. "description": "Name must be a string and is required"
  12. },
  13. "height": {
  14. "bsonType": "number",
  15. "description": "Height must be a number between 100 and 10000 and is required",
  16. "minimum": 100,
  17. "maximum": 10000
  18. }
  19. },
  20. }
  21. }
  22. })

新しい minimummaximum 属性は、に含まれる値に制約を設定します height フィールド。100より小さくしたり10000より大きくしたりできないようにします。 このコレクションは山頂の高さに関する情報を格納するために使用されるため、この範囲は理にかなっていますが、これらの属性には任意の値を選択できます。

さて、ネガティブなピークを挿入しようとすると height 値を再度指定すると、操作は失敗します。

  1. db.peaks.insertOne(
  2. {
  3. "name": "Test peak",
  4. "height": -100
  5. }
  6. )
Output
WriteError({ "index" : 0, "code" : 121, "errmsg" : "Document failed validation", . . .

この出力が示すように、ドキュメントスキーマは、各ドキュメントに保持されている文字列値を検証するようになりました。 name フィールドと、に保持されている数値 height 田畑。 各ドキュメントに格納されている配列値を検証する方法については、読み続けてください。 location 分野。

ステップ4—配列フィールドの検証

今、各ピークは nameheight 値はスキーマ検証制約によって検証されているので、注意を向けることができます。 location データの一貫性を保証するフィールド。

山の場所を指定することは、ピークが複数の国にまたがるため、予想よりも難しいです。これは、有名な8000メートル峰の多くに当てはまります。 このため、各ピークを保存するのは理にかなっています location 単なる文字列値ではなく、1つ以上の国名を含む配列としてのデータ。 と同じように height 値、それぞれを確認してください location フィールドのデータ型はすべてのドキュメントで一貫しているため、集計パイプラインを使用するときにデータを要約するのに役立ちます。

まず、いくつかの例を考えてみましょう location ユーザーが入力する可能性のある値と、有効または無効になる値を比較検討します。

MongoDBがこれらの各例を有効または無効として正しく解釈するようにするには、次の操作を実行して、 peaks コレクション:

  1. db.runCommand({
  2. "collMod": "peaks",
  3. "validator": {
  4. $jsonSchema: {
  5. "bsonType": "object",
  6. "description": "Document describing a mountain peak",
  7. "required": ["name", "height", "location"],
  8. "properties": {
  9. "name": {
  10. "bsonType": "string",
  11. "description": "Name must be a string and is required"
  12. },
  13. "height": {
  14. "bsonType": "number",
  15. "description": "Height must be a number between 100 and 10000 and is required",
  16. "minimum": 100,
  17. "maximum": 10000
  18. },
  19. "location": {
  20. "bsonType": "array",
  21. "description": "Location must be an array of strings",
  22. "minItems": 1,
  23. "uniqueItems": true,
  24. "items": {
  25. "bsonType": "string"
  26. }
  27. }
  28. },
  29. }
  30. }
  31. })

これで $jsonSchema オブジェクト、 location フィールドはに含まれています required アレイと properties 物体。 そこでは、それはで定義されています bsonTypearray を確実にするために location 値は、単一の文字列や数値ではなく、常に配列です。

The minItems プロパティは、配列に少なくとも1つの要素が含まれている必要があること、および uniqueItems プロパティはに設定されています true それぞれの中の要素を確実にするために location 配列は一意になります。 これにより、次のような値が防止されます ["Nepal", "Nepal"] 受け入れられないように。 最後に、 items サブドキュメントは、個々の配列アイテムの検証スキーマを定義します。 ここで、唯一の期待は、 location 配列は文字列である必要があります。

注:使用可能なスキーマドキュメントのプロパティは、それぞれ異なります。 bsonType また、フィールドタイプに応じて、フィールド値のさまざまな側面を検証できます。 たとえば、 number 許容値の範囲を作成するために、最小および最大許容値を定義できる値。 前の例では、 location 田畑 bsonTypearray、アレイに固有の機能を検証できます。

可能なすべての検証の選択肢の詳細については、JSONスキーマのドキュメントを参照してください。

コマンドを実行した後、MongoDBは、コレクションが新しいスキーマドキュメントで正常に変更されたことを示す短い成功メッセージで応答します。

Output
{ "ok" : 1 }

ここで、前に準備した例に一致するドキュメントを挿入して、新しいルールがどのように動作するかをテストしてみてください。 繰り返しになりますが、最小限のドキュメント構造を使用してみましょう。 name, height、 と location フィールドが存在します。

  1. db.peaks.insertOne(
  2. {
  3. "name": "Test peak",
  4. "height": 8300,
  5. "location": ["Nepal", "China"]
  6. }
  7. )

定義された検証の期待をすべて満たすため、ドキュメントは正常に挿入されます。 同様に、次のドキュメントはエラーなしで挿入されます。

  1. db.peaks.insertOne(
  2. {
  3. "name": "Test peak",
  4. "height": 8300,
  5. "location": ["Nepal"]
  6. }
  7. )

ただし、次のいずれかを実行する場合 insertOne() メソッドの場合、検証エラーが発生して失敗します。

  1. db.peaks.insertOne(
  2. {
  3. "name": "Test peak",
  4. "height": 8300,
  5. "location": "Nepal"
  6. }
  7. )
  1. db.peaks.insertOne(
  2. {
  3. "name": "Test peak",
  4. "height": 8300,
  5. "location": []
  6. }
  7. )
  1. db.peaks.insertOne(
  2. {
  3. "name": "Test peak",
  4. "height": 8300,
  5. "location": ["Nepal", "Nepal"]
  6. }
  7. )
  1. db.peaks.insertOne(
  2. {
  3. "name": "Test peak",
  4. "height": 8300,
  5. "location": ["Nepal", 15]
  6. }
  7. )

以前に定義した検証ルールに従って、 location これらの操作で提供された値は無効と見なされます。

この手順を実行した後、山頂を表す3つの主要なフィールドは、MongoDBのスキーマ検証機能によってすでに検証されています。 次のステップでは、を使用してネストされたドキュメントを検証する方法を学習します。 ascents 例としてフィールド。

ステップ5—埋め込みドキュメントの検証

この時点で、 peaks コレクションには3つのフィールドがあります— name, heightlocation —スキーマ検証によってチェックされています。 このステップでは、の検証ルールの定義に焦点を当てます。 ascents フィールド。各ピークをサミットするための成功した試みを説明します。

エベレストを表すステップ1のサンプルドキュメントでは、 ascents フィールドは次のように構成されました。

エベレスト文書
{
    "name": "Everest",
    "height": 8848,
    "location": ["Nepal", "China"],
    "ascents": {
        "first": {
            "year": 1953,
        },
        "first_winter": {
            "year": 1980,
        },
        "total": 5656,
    }
}

The ascents サブドキュメントには total その値が、指定された山の登山試行の総数を表すフィールド。 また、山の最初の冬の登りと全体的な最初の登りに関する情報も含まれています。 ただし、これらは山の説明に不可欠ではない場合があります。 結局のところ、一部の山はまだ冬に登っていないか、登山日が争われているか不明である可能性があります。 今のところ、各ドキュメントに常に必要な情報は、上昇の試行の総数であると想定してください。

スキーマ検証ドキュメントを変更して、 ascents フィールドは常に存在する必要があり、その値は常にサブドキュメントである必要があります。 このサブドキュメントには、常に total ゼロ以上の数値を保持する属性。 The firstfirst_winter このガイドではフィールドは必須ではないため、検証フォームではフィールドは考慮されず、柔軟なフォームを使用できます。

もう一度、スキーマ検証ドキュメントを置き換えます peaks 以下を実行して収集 runCommand() 方法:

  1. db.runCommand({
  2. "collMod": "peaks",
  3. "validator": {
  4. $jsonSchema: {
  5. "bsonType": "object",
  6. "description": "Document describing a mountain peak",
  7. "required": ["name", "height", "location", "ascents"],
  8. "properties": {
  9. "name": {
  10. "bsonType": "string",
  11. "description": "Name must be a string and is required"
  12. },
  13. "height": {
  14. "bsonType": "number",
  15. "description": "Height must be a number between 100 and 10000 and is required",
  16. "minimum": 100,
  17. "maximum": 10000
  18. },
  19. "location": {
  20. "bsonType": "array",
  21. "description": "Location must be an array of strings",
  22. "minItems": 1,
  23. "uniqueItems": true,
  24. "items": {
  25. "bsonType": "string"
  26. }
  27. },
  28. "ascents": {
  29. "bsonType": "object",
  30. "description": "Ascent attempts information",
  31. "required": ["total"],
  32. "properties": {
  33. "total": {
  34. "bsonType": "number",
  35. "description": "Total number of ascents must be 0 or higher",
  36. "minimum": 0
  37. }
  38. }
  39. }
  40. },
  41. }
  42. }
  43. })

ドキュメントのいずれかのフィールドにサブドキュメントが含まれている場合、そのフィールドのJSONスキーマは、メインドキュメントスキーマとまったく同じ構文に従います。 同じドキュメントを相互にネストする方法と同様に、検証スキーマもドキュメントを相互にネストします。 これにより、階層構造に複数のサブドキュメントを含むドキュメント構造の複雑な検証スキーマを簡単に定義できます。

このJSONスキーマドキュメントでは、 ascents フィールドはに含まれています required 配列、それを必須にします。 にも表示されます properties で定義されているオブジェクト bsonTypeobject、ルートドキュメント自体と同じように。

の定義に注意してください ascents 検証は、ルートドキュメントと同様の原則に従います。 それは required フィールド。サブドキュメントに含める必要のあるプロパティを示します。 また、 properties 同じ構造に従うリスト。 以来 ascents フィールドはサブドキュメントであり、その値は、より大きなドキュメントの値と同じように検証されます。

内部 ascents、 あります required 値が total、つまり ascents サブドキュメントには、 total 分野。 その後、 total 値は、 properties オブジェクト。これは常に number とともに minimum ゼロの値。

繰り返しますが、どちらも first また、 first_winter このガイドでは、フィールドは必須であり、これらの検証ルールには含まれていません。

このスキーマ検証ドキュメントを適用した状態で、最初のステップからサンプルのエベレストマウントドキュメントを挿入して、有効として確立済みのドキュメントを挿入できることを確認してください。

  1. db.peaks.insertOne(
  2. {
  3. "name": "Everest",
  4. "height": 8848,
  5. "location": ["Nepal", "China"],
  6. "ascents": {
  7. "first": {
  8. "year": 1953,
  9. },
  10. "first_winter": {
  11. "year": 1980,
  12. },
  13. "total": 5656,
  14. }
  15. }
  16. )

ドキュメントは正常に保存され、MongoDBは新しいオブジェクト識別子を返します。

Output
{ "acknowledged" : true, "insertedId" : ObjectId("619100f51292cb2faee531f8") }

検証の最後の部分が正しく機能することを確認するには、を含まないドキュメントを挿入してみてください ascents 分野:

  1. db.peaks.insertOne(
  2. {
  3. "name": "Everest",
  4. "height": 8848,
  5. "location": ["Nepal", "China"]
  6. }
  7. )

今回の操作では、ドキュメントの検証に失敗したことを示すエラーメッセージが表示されます。

Output
WriteError({ "index" : 0, "code" : 121, "errmsg" : "Document failed validation", . . . })

次に、そのドキュメントを挿入してみます ascents サブドキュメントがありません total 分野:

  1. db.peaks.insertOne(
  2. {
  3. "name": "Everest",
  4. "height": 8848,
  5. "location": ["Nepal", "China"],
  6. "ascents": {
  7. "first": {
  8. "year": 1953,
  9. },
  10. "first_winter": {
  11. "year": 1980,
  12. }
  13. }
  14. }
  15. )

これにより、再びエラーが発生します。

最後のテストとして、を含むドキュメントを入力してみてください ascents フィールドと total 値ですが、この値は負です:

  1. db.peaks.insertOne(
  2. {
  3. "name": "Everest",
  4. "height": 8848,
  5. "location": ["Nepal", "China"],
  6. "ascents": {
  7. "first": {
  8. "year": 1953,
  9. },
  10. "first_winter": {
  11. "year": 1980,
  12. },
  13. "total": -100
  14. }
  15. }
  16. )

ネガティブのため total 値の場合、このドキュメントも検証テストに失敗します。

結論

このチュートリアルに従うことで、JSONスキーマドキュメントと、それらをコレクションに保存する前にドキュメント構造を検証するためにそれらを使用する方法に精通しました。 次に、JSONスキーマドキュメントを使用してフィールドタイプを確認し、数値と配列に値の制約を適用しました。 また、ネストされたドキュメント構造でサブドキュメントを検証する方法も学習しました。

MongoDBのスキーマ検証機能は、アプリケーションレベルでのデータ検証の代わりと見なすべきではありませんが、データを意味のあるものに保つために不可欠なデータ制約に違反することをさらに防ぐことができます。 スキーマ検証の使用は、データストレージへのスキーマレスアプローチの柔軟性を維持しながら、データを構造化するための便利なツールになります。 スキーマ検証を使用すると、検証するドキュメント構造の部分と、制限のないままにしておきたい部分を完全に制御できます。

チュートリアルでは、MongoDBのスキーマ検証機能のサブセットのみを説明しました。 さまざまなMongoDBデータ型にさらに制約を適用できます。また、検証動作の厳密さを変更し、JSONスキーマを使用して既存のドキュメントをフィルタリングおよび検証することもできます。 公式の公式のMongoDBドキュメントを調べて、スキーマの検証と、データベースに保存されているデータの操作にどのように役立つかについて学ぶことをお勧めします。

モバイルバージョンを終了