Schema Validation: Data Validation at the Database Layer

Schema validation is data validation at the database layer—it can filter out invalid data even without an application layer.

The Unique Value of Database-Level Validation: Why is schema validation still necessary even with Mongoose validators? Because Mongoose validation only takes effect at the application layer— 1. Multi-application integration: If multiple microservices (Node.js/Python/Go) write to the same MongoDB database, but only the Node.js service uses Mongoose validation while the others do not; 2. Direct database operations: Operations teams using the Mongo shell to repair data or ETL scripts writing directly to the database bypass Mongoose; 3. Defense in depth: Even if there are bugs in application-layer validation, the database layer can still intercept them. Schema Validation serves as the last line of defense—it is not triggered under normal circumstances (since the application layer has already intercepted issues), but it protects data integrity in exceptional situations.

Limitations and Workarounds for Schema Validation: MongoDB Schema Validation has clear limitations—1. It does not support cross-field validation (e.g., "endDate > startDate"), which must be handled at the application layer; 2. It does not support asynchronous validation (e.g., "username must be unique," which requires a database lookup), which must be handled using a unique index; 3. It does not support conditional validation (e.g., “author is required when type='book'”), which must be handled by the application layer; 4. $jsonSchema does not support all MongoDB operators (e.g., $regex is restricted). Therefore, Schema Validation cannot fully replace application-layer validation—the correct approach is for the application layer to handle comprehensive validation (user-friendly error messages, cross-field logic, asynchronous validation), while the database layer handles fallback validation (required fields, data types, ranges, and uniqueness).

1. What You'll Learn


100%
graph LR
    A[Client-Side Document Insertion] --> B{mongo<br/>Schema Validation}
    B -->|validationLevel<br/>strict/moderate| C{Validation Rules}
    C -->|bsonType| D[Type Checking]
    C -->|required| E[Required Checks]
    C -->|pattern| F[Regular Expression Validation]
    C -->|enum| G[Enumeration Check]
    C -->|minLength| H[Length Check]

    D --> I{Through?}
    E --> I
    F --> I
    G --> I
    H --> I

    I -->|Yes + action=error| J[✅ Insertion successful]
    I -->|No + action=error| K[❌ Reject + Throw error]
    I -->|No + action=warn| L[⚠️ Allow + Warning]

    style J fill:#d4edda
    style K fill:#f8d7da

2. $jsonSchema Validator

Concept Explanation: $jsonSchema is a document schema validation language introduced in MongoDB 3.6+ that is based on the JSON Schema specification. It allows you to define structural rules that documents must satisfy at the database level—such as field types, required fields, value ranges, and regular expression patterns. Unlike application-layer validation, $jsonSchema is enforced by the MongoDB engine, and any client (Python, Java, Node.js) writing data must comply with it.

How It Works: When creating a collection with a validator, MongoDB stores the $jsonSchema rules in the collection metadata. For every insert or update operation, the engine automatically validates whether the document meets the rules before writing it. If validation fails, the system determines whether to throw an error and reject the operation or log a warning based on the validationAction.

$jsonSchema Core Keywords:

Keyword Function Example
bsonType Specify BSON type 'string', 'int', 'object', 'array'
required List of Required Fields ['email', 'username']
properties Field-Level Rule Definition { email: { bsonType: 'string' } }
pattern Regular Expression Validation '^.+@.+$' (Email Format)
enum Enumeration value ['customer', 'admin']
minimum / maximum Value Range minimum: 0, maximum: 150
minLength / maxLength String Length minLength: 3, maxLength: 30
items Rules for Array Elements { bsonType: 'string' }
minItems Minimum Array Length minItems: 1

The Relationship Between $jsonSchema and JSON Schema: MongoDB’s $jsonSchema is based on the JSON Schema Draft 4 specification, but there are several key differences— 1. It uses bsonType instead of type (because JSON Schema does not distinguish between BSON types such as int, double, decimal, and objectId); 2. additionalProperties is set to true by default (allowing undefined fields, which differs from the default in JSON Schema Draft 4); 3. It does not support $ref references (all rules must be defined inline); 4. It does not support format (e.g., email, uri, date-time; regular expressions must be used instead). Understanding these differences helps avoid the confusion of "copying code from a JSON Schema tutorial verbatim only to encounter errors."

Nested Validation with $jsonSchema: $jsonSchema supports recursive validation of nested objects and arrays—1. For nested objects, define the sub-structure using properties and required (e.g., address: {bsonType: 'object', required: ['city'], properties: {city: {bsonType: 'string'}}}); 2. For arrays, use items to define element rules (e.g., tags: {bsonType: 'array', items: {bsonType: 'string'}} to validate that all array elements are strings); 3. There is no strict limit on nesting depth, but excessive nesting can impact validation performance and readability—consider splitting into separate collections for more than three levels of nesting. Nested validation is a core advantage of the document model—while SQL requires multi-table JOINs to validate related data, MongoDB validates the entire document tree in a single pass.

Use Cases:

The Relationship Between the $jsonSchema Specification and JSON Schema: MongoDB’s $jsonSchema is based on the JSON Schema Draft 4 specification but includes BSON extensions—replacing type with bsonType (since MongoDB uses BSON rather than JSON for types) and adding BSON-specific types such as objectId, decimal, and date. Understanding this relationship is important: 1. bsonType: 'string' corresponds to JSON Schema’s type: 'string'; 2. bsonType: 'int' has no direct counterpart (JSON only has number); 3. required, properties, pattern, and enum are identical to those in JSON Schema.

Version Migration Strategy: Changes to Schema Validation require a versioning strategy—1. Adding optional fields: Low risk; deploy directly with “moderate” + “warn”; 2. Adding required fields: Medium risk; first set to “optional” → perform data migration → then set to “required”; 3. Changing field types: High risk; dual-write fields → migrate → switch → delete old fields; 4. Narrowing value ranges: Medium risk—first observe with “moderate” and “warn” → confirm no widespread violations → switch to “error.” Record the old rules for each change; roll back using collMod if necessary.

JAVASCRIPT
// === Create a collection with validation ===
db.createCollection('users', {
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['email', 'username'],
      properties: {
        email: {
          bsonType: 'string',
          pattern: '^.+@.+$',
          maxLength: 100
        },
        username: {
          bsonType: 'string',
          minLength: 3,
          maxLength: 30
        },
        age: {
          bsonType: 'int',
          minimum: 0,
          maximum: 150
        },
        role: {
          enum: ['customer', 'admin', 'moderator']
        },
        isActive: {
          bsonType: 'bool'
        }
      }
    }
  },
  validationLevel: 'strict',
  validationAction: 'error'
});

Key Points Analysis:

  1. bsonType Unlike JSON Schema’s type, MongoDB uses BSON type names (such as 'int' rather than 'number')
  2. required is a top-level keyword whose value is an array of field names; it does not belong to any property.
  3. Nested documents are defined using properties, and array elements are defined using items

Design Patterns for Nested Validation: There are three design patterns for nested validation in $jsonSchema: 1. Fully Inline Pattern (where address and item are directly nested within the $jsonSchema of the order; this provides a clear structure but results in verbose code); 2. Variable Extraction Pattern (where addressSchema and itemSchema are defined as JavaScript variables and referenced in the main schema; this offers good code reusability but requires management at the application layer); 3. Hybrid Mode (core fields are inlined, while reusable sub-structures are extracted as variables). Mode 3 is recommended for production environments—since addresses and order items may be reused across multiple collections (both orders and users have addresses), extracting them as independent variables reduces redundant definitions.

Edge Cases in Array Validation: There are several error-prone edge cases in $jsonSchema array validation—1. minItems and maxItems check the array length rather than the number of documents (an empty array [] passes minItems: 0 but fails minItems: 1); 2. items defines the rules for all elements (it does not support tuple validation where “the first 3 elements are of different types”; JSON Schema Draft 4 supports this, but MongoDB does not); 3. uniqueItems: true checks for uniqueness of array elements but may not work as expected with nested objects (objects are compared by reference rather than by depth); 4. Empty array vs. null array—an empty array [] passes validation with bsonType: 'array', but null does not (requires bsonType: ['array', 'null'] to allow null).

▶ Example 1: Nested Documents + Array Validation

JAVASCRIPT
// ShopHub Order Collection:Nested Addresses + Validation of the Order Items Array
db.createCollection('orders', {
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['userId', 'items', 'total', 'address'],
      properties: {
        userId: { bsonType: 'objectId' },
        items: {
          bsonType: 'array',
          minItems: 1,
          items: {
            bsonType: 'object',
            required: ['productId', 'qty', 'price'],
            properties: {
              productId: { bsonType: 'objectId' },
              qty: { bsonType: 'int', minimum: 1 },
              price: { bsonType: 'decimal', minimum: 0 }
            }
          }
        },
        address: {
          bsonType: 'object',
          required: ['street', 'city', 'zipCode'],
          properties: {
            street: { bsonType: 'string', minLength: 1 },
            city: { bsonType: 'string' },
            zipCode: { bsonType: 'string', pattern: '^[0-9]{5,10}$' }
          }
        },
        total: { bsonType: 'decimal', minimum: 0 }
      }
    }
  },
  validationLevel: 'moderate',
  validationAction: 'error'
});

// Test:Valid Orders
db.orders.insertOne({
  userId: ObjectId(),
  items: [{ productId: ObjectId(), qty: Int32(2), price: Decimal128('29.99') }],
  address: { street: '123 Main St', city: 'Seattle', zipCode: '98101' },
  total: Decimal128('59.98')
});
// ✅ Success

// Test: Empty items Array
db.orders.insertOne({
  userId: ObjectId(),
  items: [],
  address: { street: '123 Main St', city: 'Seattle', zipCode: '98101' },
  total: Decimal128('0')
});
// ❌ Document failed validation (minItems: 1)

3. validationAction

Concept Description: validationAction Controls MongoDB’s behavior when a validation check fails—whether to strictly reject the operation (error) or to allow it with a warning (warn). This is a critical trade-off between data integrity and business continuity.

How It Works:

The Operational Value of "warn" Mode: The core value of "warn" mode is "zero-risk deployment of new rules"—when adding a new validation rule, set it to "warn" first, monitor the logs for 1–2 weeks, and track how many existing write operations are rejected. If the violation rate is <1%, the rule is considered safe and can be switched to error mode; if the violation rate is >5%, the rule needs to be adjusted or historical data needs to be cleaned up first. This incremental deployment strategy prevents production incidents such as “widespread errors immediately upon deployment.” To query warn logs, use db.adminCommand({getLog: 'global'}) and filter for the keyword DocumentFailedValidation.

Monitoring Solution for "warn" Logs: "warn" mode logs require proactive monitoring—1. Log filtering: MongoDB "warn" logs are mixed in with other logs; after collection via Filebeat/Fluentd, filter for the keyword "DocumentFailedValidation"; 2. Alert rules: If the number of violations exceeds 10 per hour, trigger a Slack/email alert (indicating the rule may be too strict); 3. Violation Dashboard: Group and count violations by collection, field, and error type to determine which rules need adjustment; 4. Automated Reporting: Generate a daily summary report of violations (Z violations in field Y of collection X) and send it to the DBA and backend teams. The "warn" mode is not a "set-and-forget" approach, but rather a "set-and-monitor-closely" one—only through continuous monitoring can you safely switch from "warn" to "error."

Use Cases:

Stage Recommended Action Reason
Development/Testing error Detect data issues early
Initial Phase of New Rule Implementation warn Avoid disrupting business operations; monitor violations
Once the rules are stable error Enforce them to ensure data integrity
Data Migration off Temporarily disabled to prevent old data from being rejected
100%
graph LR
    A[Write Operation] --> B{Schema Validation}
    B -->|Through| C[✅ Write successful]
    B -->|Failure + action=error| D[❌ Throw Error, Reject]
    B -->|Failure + action=warn| E[⚠️ Write successful + Log Warning]

    style C fill:#d4edda
    style D fill:#f8d7da
    style E fill:#fff3cd
action Behavior Applicable Scenarios
error Insert/Update Failed (Exception Thrown) Production Environment—Data Integrity Takes Priority
warn Allowed but log a warning (do not throw an error) Phased rollout, observation period
JAVASCRIPT
// === error Pattern(Recommended Production)===
db.createCollection('users', {
  validator: { $jsonSchema: {...} },
  validationAction: 'error'
});

// === warn Pattern (Lenient) ===
db.createCollection('users', {
  validator: { $jsonSchema: {...} },
  validationAction: 'warn'
});
// Inserting an Incompatible Document:Success + Warning Log

Key Points Analysis:

  1. Before switching from "warn" to "error," we recommend first analyzing the frequency of violations in the "warn" logs.
  2. Logs in warn mode can be viewed via db.adminCommand({getLog:'global'})
  3. validationAction: 'off' does not exist; to disable validation, set validationLevel: 'off'

4. validationLevel

Concept Description: validationLevel determines which documents the validation rules apply to—only new documents (moderate) or including existing documents (strict). This is a core configuration for schema evolution and determines how new rules affect existing data.

How It Works:

Use Cases:

Scenario Recommended Level Reason
Brand-New Collection strict No historical baggage, thoroughly verified
New Rules for Existing Sets moderate Preventing Old Data from Being Updated
Data migration in progress off Temporarily disabled; will be re-enabled after migration is complete
Consistent Rules + Clean Data strict Maximum Protection
Level Behavior Applicable Scenarios
strict Validate all documents (including existing ones) New collection, clean data
moderate Verify only newly inserted/updated documents (recommended) Existing collections, phased rollout
off No verification Data migration
JAVASCRIPT
// === moderate Pattern(Recommendations)===
db.createCollection('users', {
  validator: { $jsonSchema: {...} },
  validationLevel: 'moderate'
});
// Existing dirty data is not validated,Validate only new data

Key Points Analysis:

  1. "moderate" is the most commonly used level in production environments; it does not block updates to historical dirty data.
  2. Before switching from "moderate" to "strict," you must first clean up non-compliant historical data.
  3. collMod You can dynamically modify the validationLevel without having to rebuild the collection.

Implicit Risks of "moderate": The "validate new data only" approach in "moderate" mode may seem safe, but it carries implicit risks—1. Old data can be updated an unlimited number of times without triggering validation, so dirty data may become increasingly corrupted; 2. Application code may rely on schema rules (such as assuming all documents have an email field), causing the application to crash when old data does not comply; 3. “Moderate” is not a “safe default,” but rather a “migration grace period”—you should switch to “Strict” once migration is complete. Best practice: Start with “Moderate” + “Warn” to monitor the violation rate, and switch to “Strict” + “Error” once the violation rate drops to 0.

Coordination of Data Migration and Validation: Schema validation and data migration must be coordinated—1. When adding a new required field, first set a default value (to prevent old documents from missing required fields), then use a migration script to populate historical data; 2. When adding an enum constraint, first ensure that all historical values fall within the enum range (otherwise, old data can be updated in moderate mode but will result in an error in strict mode); 3. When tightening constraints (e.g., changing maxlength from 200 to 100), first observe the behavior in warn mode to confirm there is no excessively long data before switching to error mode. Migration scripts typically use bulkWrite + $set to batch-update historical data.


5. Modifying the Validator for an Existing Set

Concept Explanation: In a production environment, schemas are not static—business iterations may require adding new fields, modifying rules, or even removing constraints. The collMod command allows you to modify validators for existing collections online, without having to rebuild the collection or take the service offline.

Important Notes on collMod: The collMod validator performs a "full replacement" rather than an "incremental merge"—you must provide the complete $jsonSchema schema with every call, even if you’re changing only one field. This means: 1. You must save the current schema before making changes (use db.getCollectionInfos() to view the existing validator); 2. The new schema must include all fields from the old schema (otherwise, fields not listed will no longer be validated); 3. It is recommended to manage $jsonSchema rules using version control (such as Git) to facilitate rollbacks and audits. To remove a validator, use an empty object { } with validationLevel: 'off', rather than deleting the validator field.

Schema Version Control Practices: $jsonSchema definitions should be included in version control—1. One JSON file per collection (e.g., validators/users.json, validators/orders.json), managed in the same repository as the application code; 2. Deployment scripts should execute collMod in the order of dependencies (users first, then orders, because orders references users._id); 3. Version Numbering: Include the version number and date of changes in a comment at the top of each schema file for easy tracking; 4. Rollback Procedure: Simply revert the schema file using Git and re-run the deployment script to roll back; 5. CI/CD Integration: Automatically execute schema migration scripts within the deployment pipeline to ensure that the code and schema are updated in sync. This set of practices eliminates the classic deployment issue of “code has changed but the database schema hasn’t.”

Rollout Strategy for Schema Migrations: Schema changes should be rolled out in phases, just like code— 1. Phase 1: Make the new field optional (moderate + warn), and monitor for 1–2 weeks to confirm there are no issues; 2. Phase 2: Use migration scripts to backfill historical data (bulkWrite + $set) to ensure all documents contain the new fields; 3. Phase 3: Set the new fields to required (strict + error), enforcing that new documents must include them; 4. Phase 4: Application code begins using the new fields (previously, it was “use if present, ignore if absent”). Each phase is deployed independently; if a problem arises, only the current phase is rolled back. Avoid implementing all changes at once—while “adding fields, populating historical data, and then setting them as required” may seem inefficient, each step is verifiable and rollback-able, making it the only way to ensure production safety.

100%
graph LR
    A[Analyzing New Demand] --> B[Design New Rules]
    B --> C[validationLevel: moderate<br/>validationAction: warn]
    C --> D[Observation Log<br/>Frequency of Violations]
    D --> E{Many violations?}
    E -->|Many| F[Adjustment Rules/Data Migration]
    E -->|Few| G[validationAction: error]
    F --> D
    G --> H[validationLevel: strict<br/>(Optional)]

    style C fill:#fff3cd
    style G fill:#d4edda
Operation Command Notes
Add Validator collMod + validator moderate to avoid affecting old data
Modification Rules collMod + new validator Full replacement, not incremental modification
Delete Verifier collMod + validator:{} + level:off For temporary deactivation
Add a required field Make new fields optional at first, then required Take a gradual approach to avoid blocking data entry

Best Practices for Schema Evolution: Schema changes in production environments require a cautious, incremental approach—1. Adding fields: First set them to optional with a default value (so that legacy data is automatically populated with the default); after running for a while to confirm there are no issues, change them to required; 2. Tightening constraints: First use validationAction: warn to monitor; after confirming there are no violations, switch to error; 3. Removing fields: First, stop writing to the field at the application layer; after confirming that legacy data is no longer being read, use $unset to clean it up in bulk; 4. Renaming fields: First, add the new field and write to both the new and old fields simultaneously; after migrating the data, delete the old field. A rollback plan is required for each step.

The Relationship Between $jsonSchema and JSON Schema: MongoDB’s $jsonSchema is based on the JSON Schema draft-4 specification but has been tailored to include support for bsonType (which extends BSON types such as ObjectId and Decimal128), required, properties, pattern, minimum/maximum, minItems/maxItems, and more. Keywords not supported: $ref (external references are not supported), definitions (reusable definitions are not supported), and anyOf/oneOf/allOf (combined validation is not supported). These limitations mean that $jsonSchema is suitable for “structural validation” (field type + range + format) but not for complex cross-field logical validation—the latter should be implemented at the Mongoose layer.

JAVASCRIPT
// === Add a validator to an existing collection ===
db.runCommand({
  collMod: 'users',
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['email', 'username'],
      properties: {
        email: { bsonType: 'string', pattern: '^.+@.+$' }
      }
    }
  },
  validationLevel: 'moderate',
  validationAction: 'error'
});

// === Modify the Validator ===
db.runCommand({
  collMod: 'users',
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['email', 'username', 'age'],  // New age Required
      properties: {
        email: { bsonType: 'string', pattern: '^.+@.+$' },
        age: { bsonType: 'int', minimum: 0 }
      }
    }
  }
});

// === Remove Validator ===
db.runCommand({
  collMod: 'users',
  validator: {},
  validationLevel: 'off'
});

Key Points Analysis:

  1. The validator for collMod performs a complete replacement, not a merge—you must write the complete rule every time you make a change.
  2. When adding a new "required" field, it is recommended to start with "moderate + warn" and switch to "strict + error" only after confirming that the existing data is acceptable.
  3. Delete the validator using an empty object {}; do not delete the "validator" field.

6. mongoose Schema vs MongoDB $jsonSchema

Concept Explanation: Mongoose Schema and MongoDB’s $jsonSchema are two complementary layers of data validation mechanisms. Mongoose performs validation at the application layer (within the Node.js process); it is flexible but applies only to Node.js clients. $jsonSchema performs validation at the database layer (within the mongod process); it is strict but applies to all clients.

Comparative Analysis:

Dimension mongoose Schema MongoDB $jsonSchema
Execution Layer Application Layer (Node.js) Database Layer (MongoDB)
Performance Verified in the application process Verified in the database
Flexibility ✅ Asynchronous validation, custom functions ❌ Static rules only
Cross-language ❌ Node.js only ✅ Works with any driver
Complex Validation ✅ Any JS code ❌ Limited to JSON Schema
Nested Validation ✅ Deep nesting + references ✅ Nested properties
Custom Error Messages ✅ Customized by field ❌ Generic error messages
Runtime Modifications ✅ Dynamic addition/removal ✅ Online modification of collMod
100%
graph LR
    A[Client Request] --> B[mongoose Schema<br/>Application-Layer Validation]
    B -->|Through| C[MongoDB $jsonSchema<br/>Database-Level Validation]
    B -->|Failure| D[❌ Application Layer Rejection<br/>Custom Error Messages]
    C -->|Through| E[✅ Write successful]
    C -->|Failure| F[❌ Database Rejection<br/>DocumentFailedValidation]

    style B fill:#cce5ff
    style C fill:#d4edda
    style D fill:#f8d7da
    style F fill:#f8d7da

Best Practices:

▶ Example 2: Mongoose + $jsonSchema Double Validation

JAVASCRIPT
// ShopHub:Two-Factor Verification for User Registration
// 1. mongoose layer: Flexible Validation + Custom Message
const userSchema = new mongoose.Schema({
  email: {
    type: String,
    required: [true, 'Email is required'],
    match: [/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, 'Invalid email format']
  },
  username: {
    type: String,
    required: true,
    minlength: [3, 'Username must be at least 3 characters'],
    maxlength: 30,
    validate: {
      validator: async function(v) {
        const count = await this.constructor.countDocuments({ username: v });
        return count === 0;
      },
      message: 'Username already exists'
    }
  },
  age: { type: Number, min: 18, max: 120 },
  role: { type: String, enum: ['customer', 'admin', 'moderator'], default: 'customer' }
});

// 2. $jsonSchema layer: Infrastructure Safety Net
db.runCommand({
  collMod: 'users',
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['email', 'username'],
      properties: {
        email: { bsonType: 'string', pattern: '^.+@.+$' },
        username: { bsonType: 'string', minLength: 3 },
        age: { bsonType: 'int', minimum: 18 },
        role: { enum: ['customer', 'admin', 'moderator'] }
      }
    }
  },
  validationLevel: 'moderate',
  validationAction: 'error'
});

// 3. Effect: Node.js client uses double verification, other clients are caught by $jsonSchema safety net

7. Schema Evolution Strategy

Concept Explanation: Schema evolution is a core operational challenge for MongoDB’s schema-free database. Although MongoDB does not require a predefined schema, production data always has an implicit structure. When business requirements change, validation rules must be modified safely without disrupting business operations.

Principles of Evolution:

  1. Incremental: optional first, required later; warn first, error later
  2. Compatibility: The new rules are compatible with existing data and do not retroactively break it.
  3. Rollback Capability: Each change is logged under the old rules, allowing for a quick rollback if necessary
  4. Data First: Migrate the data first, then tighten the rules

Checklist for Safe Schema Evolution: Different types of schema changes have varying levels of risk—1. Safe operations (can be executed directly): Adding optional fields, increasing maxLength, decreasing minimum, adding enum values, adding the $jsonSchema attribute (without changing required); 2. Caution Required (Data Migration Required First): Adding a required field, tightening minLength/minimum, removing enum values, changing bsonType; 3. High Risk (Comprehensive Assessment Required): Removing fields, changing field semantics (e.g., changing “age” from “age” to “year of birth”), changing the type of a required field. Safe operations can be performed directly in the production environment; operations requiring caution must first be validated in the staging environment; high-risk operations require a comprehensive migration plan, a rollback strategy, and a phased rollout.

Team Collaboration Guidelines for Schema Evolution: Schema changes involve multiple teams—1. Backend team: Define schema rules + write migration scripts; 2. Frontend team: Adapt forms and displays to accommodate new fields; 3. DBA team: Execute collMod + monitor database performance; 4. QA team: Verify the correctness of migration scripts + develop rollback plans. Collaboration process: 1. Backend submits a PR for schema changes (including migration scripts and rollback scripts); 2. Frontend submits a PR to synchronize and adapt; 3. Code review confirms the scope of the changes; 4. Execute migration and validate in the staging environment; 5. Roll out to production via gradual deployment (start with "warn" errors, then "error" errors); 6. Monitor for 1–2 weeks to confirm no anomalies. This standardized process prevents collaboration issues such as "the schema was changed, but the frontend team wasn’t aware."

Common Evolutionary Patterns:

Evolution Type Risk Strategy
Add a new optional field Low Add a property directly (not required)
Add a new required field Medium First optional → Data migration → Then required
Change Field Type High Dual-write Field → Migration → Switch → Delete Old Field
Delete Field Medium First remove from "required" → Verify there are no dependencies → Delete property
Tighten Value Range Medium First: moderate + warn → Confirm → error

(1) Add a New Field (Backward Compatible)

JAVASCRIPT
// ✅ Gradual Evolution:The default field is optional.
db.runCommand({
  collMod: 'users',
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['email', 'username'],  // The old field is still required
      properties: {
        email: { bsonType: 'string' },
        username: { bsonType: 'string' },
        age: { bsonType: 'int' }  // Add a Field (not required)
      }
    }
  },
  validationLevel: 'moderate'
});

(2) Modify the field type (requires data migration)

Field Type Change Process:

100%
graph LR
    A[1.Add a New Field<br/>bsonType:New Type] --> B[2.Dual Writing<br/>The application writes to both new and existing fields simultaneously]
    B --> C[3.Data Migration<br/>Old Field→New Field]
    C --> D[4.Switch Query<br/>Read New Field]
    D --> E[5.Delete Old Fields<br/>Confirm that there are no dependencies]

    style A fill:#cce5ff
    style E fill:#d4edda
JAVASCRIPT
// ⚠️ Exercise Caution When Changing Field Types
// 1. Add a dual-write field
db.runCommand({
  collMod: 'users',
  validator: { /* Add a New Field,Keep the old field */ }
});

// 2. Data Migration Script
db.users.find({ ageStr: { $exists: true } }).forEach(doc => {
  db.users.updateOne(
    { _id: doc._id },
    { $set: { age: parseInt(doc.ageStr) }, $unset: { ageStr: '' } }
  );
});

// 3. Remove the old field validation

8. Comprehensive Practical Training

Concept Overview: Comprehensive Practical Application integrates all core features of $jsonSchema into a complete product set definition—including type validation, regular expressions, enumerations, ranges, nested documents, array element validation, and more—to demonstrate the full scope of production-grade schema validation.

Production-Level Schema Design Checklist:

Check Item Keyword Is it included?
Document Type bsonType: 'object'
Required Field required
String Length minLength / maxLength
Regular Expression Pattern pattern
Value Range Minimum / Maximum
Enumeration value enum
Array element items
Nested Documents Nested Properties
validationLevel moderate
validationAction error
JAVASCRIPT
// === Create a Product Collection(Includes complete Schema Validation)===
db.createCollection('products', {
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['sku', 'title', 'price', 'category'],
      properties: {
        sku: {
          bsonType: 'string',
          pattern: '^[A-Z0-9-]+$',
          maxLength: 50
        },
        title: {
          bsonType: 'string',
          minLength: 1,
          maxLength: 200
        },
        price: {
          bsonType: 'decimal'
        },
        category: {
          enum: ['Electronics', 'Books', 'Clothing', 'Home']
        },
        stock: {
          bsonType: 'int',
          minimum: 0
        },
        tags: {
          bsonType: 'array',
          items: { bsonType: 'string' }
        }
      }
    }
  },
  validationLevel: 'moderate',
  validationAction: 'error'
});

▶ Example: Practical Guide to the MongoDB $jsonSchema Validator

JAVASCRIPT
// 1. Create a collection with validation rules
db.createCollection('users', {
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['email', 'username', 'age'],
      properties: {
        email: {
          bsonType: 'string',
          pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
          maxLength: 100
        },
        username: {
          bsonType: 'string',
          minLength: 3,
          maxLength: 30,
          pattern: '^[a-zA-Z0-9_]+$'
        },
        age: {
          bsonType: 'int',
          minimum: 18,
          maximum: 120
        },
        role: {
          enum: ['customer', 'admin', 'moderator']
        }
      }
    }
  },
  validationLevel: 'moderate',  // Validate only newly inserted records/Update
  validationAction: 'error'     // Reject Illegal Data
});

// 2. Testing Valid Data → Success
db.users.insertOne({
  email: 'alice@example.com',
  username: 'alice_2026',
  age: 28,
  role: 'customer'
});
// { acknowledged: true, insertedId: ObjectId('...') }

// 3. Testing Invalid Data → Rejected
db.users.insertOne({
  email: 'invalid-email',   // Invalid email address
  username: 'ab',            // The username is too short
  age: 15                    // Under 18 years old
});
// Throw an error:Document failed validation
// The error message includes the field name and the reason for the failure.

// 4. Modify the Validator(Add a New Rule)
db.runCommand({
  collMod: 'users',
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['email', 'username', 'age', 'phone'],
      properties: {
        email: { bsonType: 'string', pattern: '^.+@.+$' },
        username: { bsonType: 'string', minLength: 3 },
        age: { bsonType: 'int', minimum: 18 },
        phone: { bsonType: 'string', pattern: '^\+?[0-9]{10,15}$' }  // New
      }
    }
  }
});

// 5. Nested Document Validation
db.createCollection('orders', {
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['userId', 'items', 'total'],
      properties: {
        userId: { bsonType: 'objectId' },
        items: {
          bsonType: 'array',
          minItems: 1,
          items: {
            bsonType: 'object',
            required: ['productId', 'qty', 'price'],
            properties: {
              productId: { bsonType: 'objectId' },
              qty: { bsonType: 'int', minimum: 1 },
              price: { bsonType: 'decimal', minimum: 0 }
            }
          }
        },
        total: { bsonType: 'decimal', minimum: 0 }
      }
    }
  }
});

// 6. Turn Off the Verifier(For example, when migrating data)
db.runCommand({
  collMod: 'users',
  validator: {},
  validationLevel: 'off'
});

Output: Valid data is successfully inserted; invalid data is rejected, and the specific fields that failed are reported. validationLevel: moderate Ensures that existing data remains unaffected.

Operational Strategy for Schema Validation: Schema Validation requires operational support in production environments—1. Deployment Strategy: First, set validationAction: 'warn' (log only, do not reject), monitor for 1–2 weeks to confirm that validations are working correctly, then switch to error; 2. Emergency Rollback: Prepare a rollback command (db.runCommand({collMod: 'users', validator: {}, validationLevel: 'off'}) to quickly disable validation in case of false positives; 3. Data Migration: Disable validation (validationLevel: 'off') before running migration scripts, then re-enable it after migration; 4. Monitoring and Alerts: Monitor “validation failed” events in MongoDB logs; frequent failures indicate that validation rules need adjustment; 5. Version Control: Store the $jsonSchema definition in version control (JSON file + deployment script) and release it in sync with the application code.

Safe Path for Evolving Validation Rules: Modifications to schema validation rules fall into three categories—1. Relaxing rules (safe): Adding optional fields, increasing maxLength, or lowering minimum without breaking existing data; 2. Tightening rules (risky): Adding required fields, narrowing the enum range, or raising minimum—existing data may not meet the new rules; 3. Type changes (most dangerous): Changing the bsonType from string to int, etc., which will almost certainly cause validation failures. Safe evolution path: First, relax the rules (make new fields optional) → Complete the data (use scripts to populate new fields in existing documents) → Then tighten the rules (set new fields as required). Allow 1–2 weeks between each step to ensure data consistency.

❓ FAQ

Q What validations does $jsonSchema support?
A bsonType / required / properties / pattern / minLength / maxLength / minimum / maximum / enum, etc.
Q Which is better, Mongoose or $jsonSchema?
A Use both. Mongoose provides flexible validation at the application layer, while $jsonSchema acts as a safety net at the database layer.
Q Does schema validation affect performance?
A It has a minor impact. Validation is performed at the database layer, and every insert or update is validated. It can be temporarily disabled during peak periods.

📖 Summary


📝 Exercises

  1. Basic Question (⭐): Create a $jsonSchema validation for the users collection (email/username/age).
  2. Basic Question (⭐): Tests the difference in behavior between validationAction: warn and validationAction: error.
  3. Advanced Exercise (⭐⭐): Use collMod to modify the validator of an existing collection (add a new field).
  4. Advanced Problem (⭐⭐): Implement dual validation using Mongoose and $jsonSchema.
  5. Challenge Question (⭐⭐⭐): The complete $jsonSchema definition for the product collection (including nested elements, arrays, and Decimal128).
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏