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.