Concepts
Positioning
If you know the MongoDB driver, you know Mondel.
Mondel is a thin ODM (object–document mapper):
- You declare collections with
defineSchema+s.* createClientexposes typed proxies (db.users)- Writes are optionally validated with Zod derived from the schema
- Everything else is the official
mongodbdriver
There is no document class hierarchy, no global model registry, and no query language to re-learn.
Core ideas
1. Schema is the source of truth
From one schema definition Mondel derives:
| Artifact | How |
|---|---|
| Collection name on the client | Schema name (e.g. "users" → db.users) |
| MongoDB collection | collection option or same as name |
| TypeScript document shape | InferSchemaType<typeof schema> |
| Create / update input types | CreateInput / UpdateInput |
| Runtime validators | zodCreateSchema / zodUpdateSchema |
| Indexes & JSON Schema | CLI mondel push |
2. Plain objects
findOne / findMany return plain documents (POJOs + BSON types like ObjectId / Date).
No hydration into model instances. Serialize with JSON.stringify as usual (ObjectIds need care).
3. Native filters
There is no Prisma-style where: { email: { contains: "a" } }.
Use MongoDB filter syntax:
await db.users.findMany({
age: { $gte: 18, $lte: 65 },
role: { $in: ["ADMIN", "USER"] },
email: { $regex: /@example\.com$/i },
});4. Validation boundary
| Operation | Validated? |
|---|---|
create / createMany | Yes (mode-dependent) |
| Plain update objects | Yes |
$set / $setOnInsert | Yes |
$inc, $push, $unset, … | No (passed through) |
find* / aggregate | No (reads trust stored data) |
bulkWrite | No (use typed helpers when you need validation) |
Modes: strict (throw ZodError), loose (warn), off (skip).
5. Timestamps are opt-in
timestamps: true adds createdAt / updatedAt management on create/update/upsert.
Disable per call with { timestamps: false }.
6. Indexes are a deploy concern
Creating indexes on every serverless cold start is an anti-pattern.
Mondel’s recommended path: npx mondel push in CI/deploy.
7. Escape hatch is first-class
const col = db.users.getCollection();
const stream = col.watch();
await col.createIndex({ email: 1 });Anything missing on the proxy is one method away from the driver.
Type safety — honest scope
Mondel gives you:
- Compile-time checks that collection names exist on the client
- Typed field names in many helpers (
select, create input shapes) - Runtime enforcement of formats (email, min/max, enums)
Mondel does not currently:
- Narrow return types based on
selectprojections (projection is applied at runtime; TypeScript still sees the full document type) - Force every
.required()field as required in all inferred create types with perfect fidelity in every edge case
Prefer: “typed collections and validated writes” over “100% type-safe everything”.
Serverless mental model
createClient({ serverless: true }) → lightweight factory (no I/O)
connect(uri) → MongoClient.connect + proxy
request work → CRUD
db.close() → optional; platform/pool dependentFor connection limits and reuse patterns, see Client & Connections.
