Schema Definition
Monch schemas are built with Zod, giving you powerful validation with full TypeScript inference.
Basic Schema
typescript
import { collection, field } from '@codician-team/monch';
const Users = collection({
name: 'users',
schema: {
_id: field.id(), // Auto-generating ObjectId
name: field.string(), // Required string
email: field.email(), // Email validation
age: field.number().optional(), // Optional number
},
});Schema Options
Timestamps
Add automatic createdAt and updatedAt fields:
typescript
const Posts = collection({
name: 'posts',
schema: { /* ... */ },
timestamps: true,
});
// Documents now include:
// - createdAt: Date (set on insert)
// - updatedAt: Date (set on insert, updated on every update)Indexes
Define indexes for better query performance:
typescript
const Users = collection({
name: 'users',
schema: { /* ... */ },
indexes: [
// Simple index
{ key: { email: 1 } },
// Unique index
{ key: { email: 1 }, unique: true },
// Compound index
{ key: { role: 1, createdAt: -1 } },
// Text index for search
{ key: { name: 'text', bio: 'text' } },
// TTL index (auto-delete after 24 hours)
{ key: { expiresAt: 1 }, expireAfterSeconds: 86400 },
// Sparse index (only indexes documents with the field)
{ key: { optionalField: 1 }, sparse: true },
// Partial filter (only index active users)
{
key: { email: 1 },
partialFilterExpression: { status: 'active' },
},
],
});Indexes are created automatically on first connection. Disable with createIndexes: false.
Connection Options
typescript
const Users = collection({
name: 'users',
schema: { /* ... */ },
// Option 1: Explicit URI
uri: 'mongodb://localhost:27017/myapp',
// Option 2: Existing client
client: existingMongoClient,
database: 'myapp',
// Option 3: Existing Db instance
db: existingDbInstance,
// Option 4: Auto-connect (default)
// Uses MONGODB_URI environment variable
});Nested Objects
Define complex nested structures:
typescript
const Users = collection({
name: 'users',
schema: {
_id: field.id(),
name: field.string(),
profile: field.object({
bio: field.string().max(500).optional(),
avatar: field.url().optional(),
social: field.object({
twitter: field.string().optional(),
github: field.string().optional(),
}).optional(),
}),
settings: field.object({
notifications: field.boolean().default(true),
theme: field.enum(['light', 'dark', 'system']).default('system'),
}),
},
});Arrays
typescript
const Posts = collection({
name: 'posts',
schema: {
_id: field.id(),
title: field.string(),
tags: field.array(field.string()), // string[]
comments: field.array(field.object({
author: field.string(),
text: field.string(),
createdAt: field.datetime(),
})),
},
});Enums
typescript
const Orders = collection({
name: 'orders',
schema: {
_id: field.id(),
status: field.enum(['pending', 'processing', 'shipped', 'delivered']),
priority: field.enum(['low', 'medium', 'high']).default('medium'),
},
});Defaults
typescript
const Posts = collection({
name: 'posts',
schema: {
_id: field.id(),
title: field.string(),
// Static default
status: field.enum(['draft', 'published']).default('draft'),
// Dynamic default (function)
slug: field.string().default(() => generateSlug()),
// Optional with default
views: field.number().default(0),
},
});Transforms
Apply transformations during validation:
typescript
const Users = collection({
name: 'users',
schema: {
_id: field.id(),
// Trim whitespace
name: field.string().trim(),
// Lowercase
email: field.email().toLowerCase(),
// Custom transform
username: field.string()
.transform((val) => val.toLowerCase().replace(/\s+/g, '_')),
},
});Refinements
Add custom validation logic:
typescript
const Users = collection({
name: 'users',
schema: {
_id: field.id(),
password: field.string()
.min(8)
.refine(
(val) => /[A-Z]/.test(val) && /[0-9]/.test(val),
{ message: 'Password must contain uppercase letter and number' }
),
confirmPassword: field.string(),
},
});Using Zod Directly
The field helper is just Zod with extensions. You can use Zod directly:
typescript
import { collection, z } from '@codician-team/monch';
const Users = collection({
name: 'users',
schema: {
_id: z.string().transform((val) => new ObjectId(val)),
name: z.string().min(1).max(100),
email: z.string().email(),
metadata: z.record(z.string(), z.any()), // Record type
tags: z.set(z.string()), // Set type
},
});Runtime Schema Access
Access the schema at runtime for validation or introspection:
typescript
const Users = collection({
name: 'users',
schema: {
_id: field.id(),
name: field.string(),
email: field.email(),
},
});
// Access runtime schema
const schema = Users.$schema;
// Validate data manually
const result = schema.safeParse({ name: 'Alice', email: 'invalid' });
if (!result.success) {
console.log(result.error.issues);
}
// Use in other Zod operations
const PartialUser = schema.partial();
const UserWithExtra = schema.extend({ extra: z.string() });