Skip to content

Schema validation

MongoDB is schema-flexible by default: a collection will happily accept documents of wildly different shapes, which is freeing during prototyping and dangerous in production. Schema validation lets you opt back into enforcement — to declare, for a given collection, which fields must exist, what types they must be, and what values are allowed — without giving up the document model’s flexibility where you still want it. You attach the rules with a $jsonSchema validator, and from then on the server checks every write against them. It is the safety rail you add once a collection’s shape has settled.

A validator is a query expression that every document must satisfy. The $jsonSchema operator is the standard way to write one, built from three core keywords:

  • bsonType — the type a field (or the document) must be, such as "object", "string", "int", or "array".
  • required — an array of field names that must be present.
  • properties — a per-field map describing each field’s type and constraints.

Here is a validator for a members collection: every member must have a string name and an integer joined year of at least 1900, and if fines is present it must be a non-negative number.

flowchart LR
  W["Incoming write"] --> V{"Matches $jsonSchema?"}
  V -->|"Yes"| A["Accepted and stored"]
  V -->|"No, action error"| R["Rejected with a validation error"]
  V -->|"No, action warn"| L["Stored but logged as a warning"]
Each write is checked against the validator; the validationAction decides whether a failure is rejected or merely logged

Attaching a validator is part of creating the collection. The call below builds members with the rules described above. This is a real operation, so it looks slightly different in the shell and in each driver:

db.createCollection("members", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "joined"],
properties: {
name: { bsonType: "string" },
joined: { bsonType: "int", minimum: 1900 },
fines: { bsonType: "number", minimum: 0 }
}
}
},
validationLevel: "strict",
validationAction: "error"
})

A document that satisfies every rule is stored without comment:

{ "name": "Ada", "joined": 2024, "fines": 0 }

A document that breaks a rule is rejected. This one is missing the required joined field and gives name the wrong type, so the write fails with a validation error rather than being silently stored:

{ "name": 42 }

Two knobs control how the rules bite. validationLevel decides which writes are checked: "strict" (the default) validates every insert and update, while "moderate" validates inserts and updates to documents that already satisfy the schema but leaves existing invalid documents alone — useful when you add validation to a collection that already holds messy data. validationAction decides what happens on failure: "error" (the default) rejects the write, while "warn" allows it but records a warning in the server log — a gentle way to discover violations without breaking writes during a migration.

A common rollout is to begin with validationAction: "warn" and validationLevel: "moderate", watch the logs to learn how much existing data violates the new rules, fix the offenders, then tighten to "error" and "strict".

In Compass: open a collection and go to the Validation tab. You can paste or edit a $jsonSchema document there, pick the validation level and action from dropdowns, and Compass will preview which existing documents would pass or fail before you save the rules — a safe way to test a validator against real data.

  • Validation is opt-in and per-collection. A collection with no validator behaves exactly as before — nothing is enforced.
  • bsonType is stricter than JSON’s loose number handling: "int", "long", "double", and "decimal" are distinct. If a driver sends a value as a double where you required an int, the write fails — a frequent surprise.
  • required only checks that a field is present; the per-field rules in properties check its type and value. Use both together to fully pin a field down.
  • Use "moderate" plus "warn" when adding validation to an existing collection so you do not break writes to documents that predate the rules.
  • You can change or remove a validator later with the collMod command — validation is not a one-way door.
Which operator expresses a MongoDB schema validation rule?
What does the required keyword in a $jsonSchema validator do?
A validator uses validationAction set to "warn". What happens to a document that violates it?
Why might you choose validationLevel "moderate" when adding rules to an existing collection?