Chapter 23: MongoDB Schema Validation
MongoDB Schema Validation β€οΈπ
Up to now we enjoyed the freedom of MongoDB being schemaless β you can throw any document you want into any collection, different documents can have completely different fields, no problem.
But in real production applications (especially when multiple developers or multiple services write to the same collection), this freedom becomes dangerous.
- Someone accidentally writes “age”: “twenty five” instead of number 25
- Someone forgets to include “email” which your application assumes always exists
- Someone writes “status”: “activee” (typo) instead of “active”
- Someone puts “price”: -500 when price should never be negative
β Chaos. Bugs. Angry users. Late-night debugging.
Schema Validation is MongoDB’s way of saying:
βOkay, you can still be flexibleβ¦ but not completely lawless. Let me enforce some basic rules so the data stays clean, consistent and safe.β
1. What Exactly is Schema Validation?
Schema validation is a collection-level rule that MongoDB enforces every time someone tries to insert or update a document in that collection.
- You define the rules when you create the collection (or later with collMod)
- Rules are written using JSON Schema (a standard vocabulary β MongoDB supports draft 4 + some extensions)
- Validation can be strict or moderate (more about this soon)
- When a write violates the rules β MongoDB rejects the operation and throws an error
2. Three Levels of Strictness (Very Important to Understand)
| Validation Level | What happens when document is invalid? | When to use it | Default when you enable validation |
|---|---|---|---|
| strict | All fields must follow the schema (even fields not mentioned in schema are forbidden) | Very controlled collections (financial, medical, config) | No β you must set it explicitly |
| moderate | Only fields mentioned in schema are validated. Extra fields are allowed | Most real-world apps (best balance) | Yes β this is the default |
| off | No validation (default behavior of MongoDB) | Prototyping / very flexible collections | Yes (if you never set validator) |
Teacher recommendation 2026: β Start with moderate in almost all production cases β Use strict only when you really want to forbid any undocumented field
3. Hands-on β Let’s Create & Test Schema Validation
Open mongosh and let’s do it step by step.
Step 1: Create collection with validation (recommended way)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
db.createCollection("employees", { validator: { $jsonSchema: { bsonType: "object", required: ["name", "empId", "department", "salary"], // these fields MUST exist properties: { name: { bsonType: "string", description: "must be a string and is required" }, empId: { bsonType: "string", pattern: "^EMP-[0-9]{4}$", // regex: EMP- followed by 4 digits description: "must match EMP-XXXX format" }, department: { enum: ["IT", "HR", "Finance", "Marketing", "Sales"], description: "can only be one of the allowed values" }, salary: { bsonType: "double", minimum: 25000, description: "must be a number >= 25000" }, joinDate: { bsonType: ["date", "null"], description: "optional date" }, skills: { bsonType: "array", items: { bsonType: "string" }, description: "array of strings" }, isActive: { bsonType: "bool", description: "boolean flag" } }, additionalProperties: true // β allows extra fields (moderate behavior) } }, validationLevel: "moderate", // default anyway validationAction: "error" // reject invalid writes (can be "warn" in some cases) }) |
Step 2: Test β Try correct insert
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
db.employees.insertOne({ name: "Rahul Sharma", empId: "EMP-2026", department: "IT", salary: 85000.50, joinDate: new Date(), skills: ["MongoDB", "Node.js", "React"], isActive: true, // extra undocumented field β allowed in moderate phone: "9876543210" }) |
β Success!
Step 3: Try invalid inserts β watch MongoDB reject them
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
// Missing required field "empId" db.employees.insertOne({ name: "Priya", department: "HR", salary: 65000 }) // β MongoServerError: Document failed validation // Wrong type for salary db.employees.insertOne({ name: "Amit", empId: "EMP-9999", department: "Finance", salary: "very high" // β string instead of number }) // β fails // Invalid enum value db.employees.insertOne({ name: "Sneha", empId: "EMP-7777", department: "Support", // not in enum list salary: 45000 }) // β fails // empId wrong pattern db.employees.insertOne({ name: "Vikram", empId: "E2026", // does not match ^EMP-[0-9]{4}$ department: "IT", salary: 72000 }) // β fails |
Step 4: Update also gets validated!
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// First insert valid document db.employees.insertOne({ name: "Priya Patel", empId: "EMP-2025", department: "HR", salary: 68000 }) // Try invalid update db.employees.updateOne( { empId: "EMP-2025" }, { $set: { salary: -1000 } } // negative salary β forbidden ) // β fails validation |
4. Quick Summary Table β Most Useful JSON Schema Keywords
| Keyword | Purpose | Example Value |
|---|---|---|
| bsonType | Enforce data type | “string”, “double”, “objectId”, “date”, “array” |
| required | Fields that must exist | [“name”, “email”, “status”] |
| enum | Only allow specific values | [“active”, “inactive”, “pending”] |
| minimum / maximum | Numeric range | minimum: 0, maximum: 1000000 |
| pattern | Regex for strings | “^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$” (email) |
| items | Validate array elements | { bsonType: “string” } |
| additionalProperties | true/false/object schema for extra fields | true (moderate), false (strict) |
5. How to Add / Modify Validation on Existing Collection
|
0 1 2 3 4 5 6 7 8 9 10 11 |
db.runCommand({ collMod: "employees", validator: { $jsonSchema: { ... same schema ... } }, validationLevel: "moderate", validationAction: "error" }) |
6. Mini Exercise β Try Right Now!
- Create a products collection with validation:
- required: name, price, category
- price β₯ 0 and number
- category in [“Electronics”, “Clothing”, “Books”]
- sku matches pattern “^PROD-[A-Z0-9]{6}$”
- Try few valid & invalid inserts
- Try to update price to negative β see rejection
Understood beta? Schema validation is not about making MongoDB “like SQL” β it’s about adding just enough safety rails so your data stays trustworthy without losing the flexibility that makes MongoDB great.
Next class β what shall we do?
- Deep dive into more advanced JSON Schema (oneOf, allOf, dependencies)?
- How to bypass validation temporarily (when importing legacy data)?
- Schema validation + aggregation (validate existing data)?
- Or back to building a small app with validation + CRUD + aggregation?
Tell me β class is yours! πβ€οΈ
Any doubt about schema validation? Ask freely β we’ll test more rules together π
