skip to content

How do you make a MongoDB collection reject documents that lack required fields?

level: juniorimportance: must knowfreq 55%

answer

  1. MongoDB enforces nothing by default
  2. the rule lives in the collection's options
  3. a query expression the document must match
  4. createCollection takes a validator option
  5. $jsonSchema with required and bsonType

basics

~20 s

Attach a validator to the collection — normally a $jsonSchema object listing required fields and their bsonType — using createCollection or collMod. MongoDB then checks every insert and update against it and rejects writes that break the rules.

solid answer

~40 s

MongoDB stores whatever BSON you hand it unless the collection carries a **validator**. A validator is a query expression kept in the collection's options; the usual form is `$jsonSchema`, where `required` lists the field names a document must contain and `properties` constrains each field with keywords like `bsonType`, `enum`, `minimum` or `maxLength`. You attach it with `db.createCollection("orders", { validator: { $jsonSchema: { ... } } })`, or add or replace it later on an existing collection with the `collMod` command. From then on every insert and every update is checked; by default (`validationAction: "error"`) a document that fails is rejected with a write error naming the rule it broke. Documents already stored are untouched — validation runs on writes, not retroactively.

go deeper

for a junior

Know that a MongoDB collection accepts anything until you attach a validator, and be able to write a small $jsonSchema with required and properties by hand.

for a middle

Explain where the validator lives, which writes it is evaluated against, and why bsonType exists alongside type. Be ready to add one to an existing collection with collMod.

for a senior

Show judgment about how strict to be: additionalProperties: false versus an open document, which fields genuinely must be required, and how a validator interacts with rolling deploys that add fields.

for a principal

Own the policy question of which collections carry validators at all, who reviews changes to them, and how bypassDocumentValidation in restore and migration tooling fits into that guarantee.

## MongoDB checks nothing until you ask it to A MongoDB collection has no declared shape. Two documents in the same collection can have completely different fields and completely different types for the same field name. That is deliberate, but it means nothing stops a buggy service from writing `{ total: "12.50" }` next to `{ total: 12.50 }`, or omitting `customerId` entirely. Server-side **document validation** is the mechanism that closes that hole for the collections where you want it closed. ## What a validator actually is A validator is a query expression stored in the collection's options. Any document a write would produce must match that expression. Two forms exist: - A plain query predicate — `{ qty: { $gt: 0 } }` — which reads exactly like a `find()` filter. - A `$jsonSchema` expression, which is the form nearly everyone uses because it can describe a whole document tree in one place. You set it when creating the collection: ```js db.createCollection("orders", { validator: { $jsonSchema: { bsonType: "object", required: ["customerId", "status"], properties: { customerId: { bsonType: "objectId" }, status: { enum: ["new", "paid", "shipped"] } } } } }) ``` or add, replace or remove it later with `db.runCommand({ collMod: "orders", validator: { ... } })`. To see what a collection currently enforces, read `db.getCollectionInfos({ name: "orders" })` and look at `options.validator`, `options.validationLevel` and `options.validationAction`. ## The keywords you will actually use - `bsonType` — the type of the value, expressed with BSON aliases: `"object"`, `"string"`, `"int"`, `"long"`, `"double"`, `"decimal"`, `"bool"`, `"date"`, `"objectId"`, `"array"`, `"binData"`. It accepts an array of aliases when several types are legal. - `required` — an array of field names that must be present. It says nothing about their types; pair it with `properties`. - `properties` — a map from field name to a sub-schema. Sub-schemas nest, so an embedded object or an array element gets its own rules (`items` describes array elements). - `enum` — the closed list of allowed values for a field. - Value constraints — `minimum`/`maximum` for numbers, `minLength`/`maxLength`/`pattern` for strings, `minItems`/`maxItems`/`uniqueItems` for arrays. - `additionalProperties: false` — forbids any field not named in `properties`. Powerful, and the fastest way to break a rolling deploy that adds a field, so use it knowingly. - `description` and `title` — free text that shows up in the validation error, which is the difference between a debuggable rejection and a mystery. ## bsonType versus type Both exist. `type` is the standard JSON Schema keyword and only knows JSON type names — `"string"`, `"number"`, `"object"`, `"array"`, `"boolean"`, `"null"`. It cannot express an ObjectId, a Date, or the difference between a 32-bit int and a double, because JSON has no such notion. `bsonType` knows the full BSON type list. Use `bsonType` unless you have a specific reason not to; `bsonType: "objectId"` and `bsonType: "int"` are the two cases that bite people first. ## When the rules run Validation is a write-path check. Inserts are validated, and updates are validated against the resulting document — so an update that removes a required field is rejected just like an insert that never had it. Deletes are unaffected. Documents already in the collection when the validator is attached are not scanned, not rewritten and not flagged; they are only ever judged when something writes to them. Privileged callers, and tools such as restore utilities, can pass `bypassDocumentValidation: true` on a write to skip the check entirely, so a validator is a guardrail for your application code rather than an inviolable law. ## What it deliberately does not do A validator only accepts or rejects. It never fills in a default value — MongoDB's `$jsonSchema` does not support the JSON Schema `default` keyword — and it never coerces `"12.50"` into a number. It also cannot look at any document other than the one being written, so uniqueness is a unique index's job, not a validator's. Treat it as a shape gate at the door, and keep business invariants that span documents somewhere that can actually see them.

  • Does attaching a validator change or reject the documents already stored in the collection?
    No. Validation runs only on inserts and updates. Existing documents are not scanned, rewritten or removed, and they keep being readable. A stored document that breaks the new rules is only judged when something writes to it — and even then, `validationLevel: "moderate"` deliberately skips updates to documents that already fail.
  • When would you use bsonType instead of the standard type keyword?
    Almost always. `type` only understands JSON type names, so it cannot say "this must be an ObjectId", "this must be a Date", or "this must be a 32-bit int rather than a double". `bsonType` accepts the BSON aliases — `objectId`, `date`, `int`, `long`, `decimal`, `binData` — which is what documents actually contain.
  • Can a validator be something other than $jsonSchema?
    Yes. Any query expression works, for example `{ qty: { $gt: 0 } }`, or `$expr` to compare two fields of the same document. A few operators are disallowed inside validators: `$near`, `$nearSphere`, `$text` and `$where`. You can also combine forms with `$and` to sit a `$expr` rule alongside a `$jsonSchema` one.

saying these in an interview costs you the question

  • Says MongoDB cannot enforce structure at all because it is schemaless
  • Thinks adding a validator deletes or repairs existing non-conforming documents
  • Expects the validator to supply default values for missing fields
  • Believes required also constrains the field's type
  • Uses type: 'objectId', which is not a JSON Schema type name

context