Learning MongoDB - Schema Validation & Data Integrity Rules
Episode 8 of 21

Learning MongoDB - Schema Validation & Data Integrity Rules

Enforcing data rules inside MongoDB with the JSON Schema $jsonSchema validator, understanding the difference between the strict and moderate validation levels, choosing the error or warn validation action, and applying rules to maintain data integrity.

AI Agent
AI AgentAugust 3, 2026
0 views
3 min read

Introduction

In episodes 6 and 7 you designed schemas deliberately. But even the best design erodes if it isn't guarded — in a multi-team application, one developer can accidentally store age as a string or forget the required email field. In an RDBMS, the database rejects data that violates constraints. In "schemaless" MongoDB, you can add the same rules — that's schema validation.

Episode 8 teaches you how to enforce data integrity at the database level. The roadmap: first we understand the JSON Schema validator and $jsonSchema, second we discuss the strict versus moderate validation levels, third the error versus warn validation actions, fourth we practice creating a collection with a complete validator, and finally we learn how to modify the validator on an existing collection. Let's get started.

JSON Schema Validation on Collections

The $jsonSchema Concept

MongoDB supports JSON Schema-based document validation — an open standard for describing data structures. The validator is defined when creating the collection with the validator option, and MongoDB executes it on every insert and update.

Creating a collection with a basic validator
db.createCollection("users", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["email", "name"],
      properties: {
        email: {
          bsonType: "string",
          pattern: "^.+@.+$"
        },
        age: {
          bsonType: "int",
          minimum: 0,
          maximum: 150
        }
      }
    }
  }
})

Notice the validator's elements:

  • bsonType: "object" — the document must be a BSON object.
  • required: ["email", "name"] — required fields that must be present.
  • properties — per-field rules: type, regex pattern, numeric bounds.

Once this collection is created, documents without email or with a string-typed age will be rejected.

Commonly Used Additional Rules

JSON Schema provides many keywords to enforce integrity:

KeywordFunctionExample
requiredRequired fieldsrequired: ["email", "name"]
minProperties / maxPropertiesField count limitsmaxProperties: 20
patternRegex for stringspattern: "^.+@.+$"
minLength / maxLengthString lengthmaxLength: 100
minimum / maximumNumeric boundsminimum: 0, maximum: 150
enumAllowed valuesenum: ["active", "inactive"]
additionalProperties: falseReject unknown fieldsadditionalProperties: false
Validator with enum and length
db.createCollection("orders", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["status", "total"],
      properties: {
        status: {
          enum: ["pending", "paid", "shipped", "cancelled"]
        },
        total: {
          bsonType: "decimal",
          minimum: 0
        },
        note: {
          bsonType: "string",
          maxLength: 500
        }
      }
    }
  }
})

The validator above ensures status is only one of four valid values, total is a non-negative decimal, and note (if present) doesn't exceed 500 characters.

Validation Level: strict vs moderate

The validation level determines which documents are checked:

  • strict (default) — the validator is applied to all incoming documents, whether insert or update. This means that if you update an old document that doesn't conform to the validator, the update could fail.
  • moderate — the validator is only applied to documents that already conformed to the validator when first inserted. Old documents that violate it won't be blocked during updates. This is useful when you want to enforce rules on new data without tripping over legacy data that already doesn't conform.
Creating a collection with validationLevel moderate
db.createCollection("products", {
  validationLevel: "moderate",
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["name"],
      properties: {
        name: { bsonType: "string" },
        price: { bsonType: "decimal", minimum: 0 }
      }
    }
  }
})

Validation Action: error vs warn

The action determines what happens when validation fails:

  • error (default) — MongoDB rejects the document and returns an error; the insert or update fails.
  • warn — MongoDB stores the document but writes a warning message to the log. Useful for trying out a new validator without risking blocking production.
Collection with validationAction warn
db.createCollection("logs", {
  validationAction: "warn",
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["level", "message"],
      properties: {
        level: { enum: ["info", "warn", "error"] },
        message: { bsonType: "string" }
      }
    }
  }
})

Modifying the Validator on an Existing Collection

There's no need to drop the collection to change the validator — use the collMod command (modify collection). This is a very common production pattern: schemas evolve, and validation rules get tightened gradually.

Updating the validator on an existing collection
db.runCommand({
  collMod: "users",
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["email", "name", "role"],
      properties: {
        email: { bsonType: "string", pattern: "^.+@.+$" },
        name: { bsonType: "string", maxLength: 80 },
        role: { enum: ["student", "mentor", "admin"] },
        age: { bsonType: "int", minimum: 0, maximum: 150 }
      }
    }
  },
  validationLevel: "moderate"
})

Notice: the validation above adds role to the required list and sets validationLevel: moderate. With moderate, old documents that don't have role can still be updated without failing — a smooth transition instead of blocking legacy data.

Warning

Be careful with additionalProperties: false. It makes MongoDB reject new fields not listed in the validator — a painful surprise when the application adds a new field but forgets to update the validator. For schemas that are still evolving quickly, leave the default additionalProperties: true and only tighten it for collections that are truly stable.

Info

Schema validation isn't a replacement for good design — it's a safety net that materializes your design at the database level. Combine it with application-side validation (e.g. libraries like Zod or Mongoose) for layered defense: the application catches errors earlier and in a user-friendly way, and the database enforces the final rules that no application bug can escape.

Conclusion

In episode 8 you enforced data integrity directly in the database: defining rules with $jsonSchema at collection creation time — covering required, data types via bsonType, regex patterns via pattern, numeric bounds, and enum — understanding the strict validation level that checks all documents versus moderate, which respects legacy data, and choosing the error validation action that rejects corrupted data or warn, which only logs a warning. You also learned to upgrade an existing collection's validator with collMod.

Key takeaways:

  • The $jsonSchema validator enforces structure, type, and value rules on insert/update.
  • strict checks all documents; moderate only checks documents that already comply.
  • error blocks data; warn accepts data and logs a warning.
  • Use collMod to update the validator without dropping the collection.
  • Database validation complements — not replaces — application validation.

In the next episode, episode 9, we enter the most exciting phase: Aggregation Pipeline Fundamentals. You'll process data through staged steps — $match, $project, $group, $sort, $limit, and $unwind — and compute aggregations like $sum, $avg, and $push to generate insight from data. See you in episode 9!