mongoui

Solution

Analyze your MongoDB schema and catch type drift

MongoDB has a flexible schema, which is another way of saying it drifts. A field that was always a number shows up as a string in newer documents, and a query silently stops matching. Here is how to find the drift and stop it.

Last reviewed July 4, 2026

MongoDB has a flexible schema, which is a polite way of saying it drifts. There is no column definition stopping a field from being an integer in one document and a string in the next. That flexibility is useful right up until a query filters on that field and silently stops matching the documents where the type changed. Analyzing your schema is how you find those splits before they turn into a support ticket.

Sample the real shape of a field

You do not need a schema definition to read your schema, because the documents already have one. Group a field by its BSON type and count:

db.users.aggregate([
  { $group: { _id: { $type: "$age" }, count: { $sum: 1 } } }
])
{ _id: "int",    count: 48120 }
{ _id: "string", count: 213 }     // the drift
{ _id: "missing", count: 8 }

Almost every age is an integer, a couple hundred are strings, and a handful are missing entirely. That is type drift, and it is exactly the kind of thing a row view hides and an aggregation makes obvious. Run it per field on the columns your queries depend on.

How drift breaks a query

A field that has always been a number shows up as a string in a slice of newer documents, because an upstream change slipped through without a migration. The query that filters on it silently stops matching those rows:

db.users.find({ age: { $gte: 18 } })   // skips the "18" strings

{ $gte: 18 } compares against numbers. The documents where age is the string "18" do not match, and nobody notices until a count comes back low. The schema drift was invisible in a document browser and obvious the moment you grouped by type.

Enforce the shape going forward

Once you have found and fixed the drift, stop the next one at the door with schema validation. MongoDB can reject writes that do not match a $jsonSchema:

db.runCommand({
  collMod: "users",
  validator: { $jsonSchema: {
    bsonType: "object",
    required: ["email", "age"],
    properties: {
      email: { bsonType: "string" },
      age:   { bsonType: "int" }
    }
  } }
})

New writes that send age as a string are rejected instead of quietly stored. The schema validation docs cover the full operator set, including how to warn instead of reject while you migrate. If you are designing the collection from scratch, how to design a MongoDB schema covers the modeling decisions first.

Or run the schema doctor

mongoui's Schema doctor samples a collection and reports field shapes, type drift, and missing fields in one pass, grounded in your actual documents rather than a model file. It is the answer to "analyze schema" without writing an aggregation per field: point it at the collection and read the mismatches.

The sampling happens locally. The engine runs on your machine and connects straight to your database, so the documents it samples never leave your network. Find the type split before the query does, add the validator, and let the flexible schema stay flexible where you want it and firm where you do not.

Frequently asked questions

How do I analyze a MongoDB schema?

Sample the collection and group by field type. db.users.aggregate([{ $group: { _id: { $type: "$age" }, count: { $sum: 1 } } }]) shows how many documents store age as an int versus a string versus missing. Run it per field to see the real shape of your data, not the shape you assumed.

What is schema validation in MongoDB?

A rule set attached to a collection with $jsonSchema that rejects writes which do not match. You define required fields and their types, and MongoDB enforces them going forward. It is how you stop drift after you have cleaned it up. See the schema validation docs for the full operator list.

How do I find type drift in MongoDB?

Group a field by its BSON type across the collection. If one field comes back as both int and string, that split is the drift. It usually happens when an upstream change writes a different type without a migration, and it quietly breaks queries that filter on that field.

Does MongoDB have a schema?

MongoDB does not require one, but your data has one whether you declared it or not. Every collection has an implicit shape: the fields, types, and structure its documents actually use. Analyzing that implicit schema is how you catch the mismatches a flexible model lets through.