MongoDB has a flexible document model, but an application still benefits from clear rules for required fields, BSON types, ranges, and allowed values. Schema validation applies these rules on the server whenever documents are inserted or updated.
Validation helps protect a collection from malformed data produced by scripts, migrations, older application versions, or manual writes. It complements application validation rather than replacing it.
Design validation from real document requirements. Rules that are too loose allow inconsistent data, while rules that are too strict can block legitimate application changes.
How MongoDB Schema Validation Works
A collection validator can use $jsonSchema, query expressions, or both. MongoDB supports a subset of JSON Schema draft 4 and adds bsonType so you can validate BSON-specific types such as objectId, date, int, and decimal.
Create a Collection with JSON Schema Validation
Pass a validator when you create the collection. Use required for mandatory fields and properties for field-specific rules.
Example:
// Create an orders collection with server-side validation
db.createCollection("orders", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["customerId", "status", "total", "createdAt"],
properties: {
customerId: {
bsonType: "objectId",
description: "customerId must be an ObjectId and is required"
},
status: {
enum: ["pending", "paid", "shipped", "cancelled"],
description: "status must be an allowed order state"
},
total: {
bsonType: "decimal",
minimum: 0,
description: "total must be a non-negative Decimal128 value"
},
createdAt: {
bsonType: "date",
description: "createdAt must be a BSON date"
}
}
}
},
validationLevel: "strict",
validationAction: "error"
})
The description text can appear in validation error details, making a rejected write easier to diagnose.
Insert Valid Documents
BSON types matter. A JavaScript number is not automatically a Decimal128 value, and a text date is not a BSON date.
// This document satisfies every declared rule
db.orders.insertOne({
customerId: ObjectId("64f0b55f9d4f3f2a1c8e1234"),
status: "paid",
total: Decimal128("1499.00"),
createdAt: new Date()
})
Understand a Validation Error
An invalid insert or update fails with a document validation error when validationAction is error. Current server versions return details that identify failed operators and fields, but scripts should not depend on the exact human-readable error layout.
// Rejected: status is not allowed and total has the wrong BSON type
db.orders.insertOne({
customerId: ObjectId(),
status: "complete",
total: 1499,
createdAt: new Date()
})
Important JSON Schema Keywords
| Keyword | Use |
|---|---|
| bsonType | Require one or more BSON types |
| required | Require named properties |
| properties | Define rules for individual fields |
| enum | Allow only listed values |
| minimum and maximum | Limit numeric values |
| minLength and maxLength | Limit string length |
| items | Validate array elements |
| additionalProperties | Allow or reject undeclared fields |
MongoDB does not support every JSON Schema keyword. For example, use BSON int or long instead of the JSON Schema integer type, and check the current manual before adopting a keyword.
Validate Nested Documents and Arrays
// Add nested shipping and line-item rules
{
shipping: {
bsonType: "object",
required: ["city", "postalCode"],
properties: {
city: { bsonType: "string", minLength: 2 },
postalCode: { bsonType: "string", pattern: "^[0-9]{6}$" }
}
},
items: {
bsonType: "array",
minItems: 1,
items: {
bsonType: "object",
required: ["sku", "quantity"],
properties: {
sku: { bsonType: "string" },
quantity: { bsonType: "int", minimum: 1 }
}
}
}
}
If you set additionalProperties: false, include _id in the allowed properties because MongoDB adds it to documents.
Add or Change Validation on an Existing Collection
Use the collMod database command. Existing documents are not automatically rewritten, so inspect them before enabling strict rejection.
// Replace the validator on an existing collection
db.runCommand({
collMod: "orders",
validator: {
$jsonSchema: {
bsonType: "object",
required: ["status", "total"],
properties: {
status: { enum: ["pending", "paid", "shipped", "cancelled"] },
total: { bsonType: "decimal", minimum: 0 }
}
}
},
validationLevel: "moderate",
validationAction: "warn"
})
Choose a Validation Level
- strict validates every insert and every updated document. It is the default.
- moderate validates new documents and updates to documents that are already valid, while allowing some legacy invalid documents to be updated during migration.
- off disables validation when supported by the selected operation and server version.
Choose a Validation Action
error rejects invalid writes and is the default. warn permits the write but records the violation in the server log, which is useful during rollout. MongoDB 8.1 added errorAndLog, which rejects and logs the violation; avoid it if you must downgrade to a version that does not support it.
Find Existing Invalid Documents
Use the same $jsonSchema expression inside a query. Wrap it in $nor to locate documents that do not match before changing enforcement.
// Find documents that fail the planned schema
db.orders.find({
$nor: [{
$jsonSchema: {
bsonType: "object",
required: ["status", "total"],
properties: {
status: { enum: ["pending", "paid", "shipped", "cancelled"] },
total: { bsonType: "decimal", minimum: 0 }
}
}
}]
})
Validation and Indexes
Validation controls document shape; indexes enforce uniqueness and improve query access. Use a unique index for a field such as an order number because JSON Schema cannot guarantee uniqueness across documents.
// Enforce uniqueness separately from document validation
db.orders.createIndex({ orderNumber: 1 }, { unique: true })
Best Practices
- Test the schema against representative existing documents.
- Use descriptive rules so errors explain the expected value.
- Roll out with warn or moderate when legacy data needs migration.
- Version validation changes alongside application changes.
- Keep uniqueness and query performance requirements in indexes.
- Monitor rejected writes and log warnings after deployment.
Conclusion
MongoDB schema validation keeps flexible documents within deliberate boundaries. Define BSON-aware rules, test valid and invalid writes, select the appropriate enforcement level and action, and migrate legacy data carefully. Combined with application validation and indexes, it provides a reliable data-quality layer at the database boundary.