0
# Schema Definition
1
2
Define document structure, validation rules, indexes, virtual properties, and middleware with a rich schema type system for MongoDB collections.
3
4
## Capabilities
5
6
### Schema Constructor
7
8
Create schema definitions with type specifications, validation rules, and configuration options.
9
10
```javascript { .api }
11
/**
12
* Creates a new Schema
13
* @param definition - Schema field definitions
14
* @param options - Schema configuration options
15
*/
16
class Schema<T = any> {
17
constructor(definition?: SchemaDefinition<T>, options?: SchemaOptions);
18
}
19
20
// Create schemas with field definitions
21
const userSchema = new Schema({
22
name: { type: String, required: true },
23
email: { type: String, unique: true },
24
age: { type: Number, min: 0, max: 120 },
25
tags: [String],
26
profile: {
27
bio: String,
28
website: { type: String, match: /^https?:\/\// }
29
}
30
});
31
```
32
33
### Schema Methods
34
35
Methods for modifying and configuring schemas after creation.
36
37
```javascript { .api }
38
interface Schema<T> {
39
/**
40
* Add fields to the schema
41
* @param obj - Field definitions to add
42
* @param prefix - Path prefix for nested fields
43
* @returns this schema
44
*/
45
add(obj: SchemaDefinition<T>, prefix?: string): this;
46
47
/**
48
* Get or set a schema path
49
* @param path - Path name
50
* @param schemaType - SchemaType to set (optional)
51
* @returns SchemaType or this schema
52
*/
53
path(path: string): SchemaType | undefined;
54
path(path: string, schemaType: SchemaType): this;
55
56
/**
57
* Create a virtual property
58
* @param name - Virtual property name
59
* @param options - Virtual options
60
* @returns VirtualType instance
61
*/
62
virtual(name: string, options?: any): VirtualType;
63
64
/**
65
* Define an index
66
* @param fields - Index specification
67
* @param options - Index options
68
* @returns this schema
69
*/
70
index(fields: any, options?: any): this;
71
72
/**
73
* Add pre-middleware hook
74
* @param method - Method name to hook
75
* @param fn - Middleware function
76
* @returns this schema
77
*/
78
pre(method: string, fn: Function): this;
79
pre<T>(method: string, fn: (this: T, next: Function) => void): this;
80
81
/**
82
* Add post-middleware hook
83
* @param method - Method name to hook
84
* @param fn - Middleware function
85
* @returns this schema
86
*/
87
post(method: string, fn: Function): this;
88
post<T>(method: string, fn: (this: T, doc: T, next: Function) => void): this;
89
90
/**
91
* Add instance method to documents
92
* @param name - Method name
93
* @param fn - Method function
94
* @returns this schema
95
*/
96
method(name: string, fn: Function): this;
97
method(methods: { [name: string]: Function }): this;
98
99
/**
100
* Add static method to model
101
* @param name - Method name
102
* @param fn - Method function
103
* @returns this schema
104
*/
105
static(name: string, fn: Function): this;
106
static(methods: { [name: string]: Function }): this;
107
108
/**
109
* Register a plugin
110
* @param plugin - Plugin function
111
* @param opts - Plugin options
112
* @returns this schema
113
*/
114
plugin(plugin: Function, opts?: any): this;
115
116
/**
117
* Create a copy of this schema
118
* @returns Cloned schema
119
*/
120
clone(): Schema<T>;
121
122
/**
123
* Get array of schema paths
124
* @param options - Path iteration options
125
* @returns Array of path names
126
*/
127
paths(options?: any): string[];
128
129
/**
130
* Iterate over schema paths
131
* @param fn - Function called for each path
132
* @returns this schema
133
*/
134
eachPath(fn: (path: string, schemaType: SchemaType) => void): this;
135
136
/**
137
* Create discriminator schema
138
* @param name - Discriminator name
139
* @param schema - Discriminator schema
140
* @param value - Discriminator value
141
* @returns Discriminator constructor
142
*/
143
discriminator<U>(name: string, schema: Schema<U>, value?: string): Model<U>;
144
145
/**
146
* Create new schema with selected paths only
147
* @param paths - Array of paths to include
148
* @param options - Schema options
149
* @returns New schema with selected paths
150
*/
151
pick<T>(paths: string[], options?: SchemaOptions): Schema<T>;
152
153
/**
154
* Create new schema excluding specified paths
155
* @param paths - Array of paths to exclude
156
* @param options - Schema options
157
* @returns New schema without excluded paths
158
*/
159
omit<T>(paths: string[], options?: SchemaOptions): Schema<T>;
160
161
/**
162
* Remove all indexes from schema
163
* @returns this schema
164
*/
165
clearIndexes(): this;
166
167
/**
168
* Remove specific index from schema
169
* @param index - Index specification to remove
170
* @returns this schema
171
*/
172
removeIndex(index: string | any): this;
173
174
/**
175
* Define Atlas search index
176
* @param description - Search index definition
177
* @returns this schema
178
*/
179
searchIndex(description: SearchIndexDescription): this;
180
181
/**
182
* Convert schema to JSON Schema format
183
* @param options - Conversion options
184
* @returns JSON Schema representation
185
*/
186
toJSONSchema(options?: { useBsonType?: boolean }): Record<string, any>;
187
188
/**
189
* Add method calls to queue for later execution
190
* @param name - Method name
191
* @param args - Method arguments
192
* @returns this schema
193
*/
194
queue(name: string, args: any[]): this;
195
}
196
197
// Schema Properties
198
interface Schema<T> {
199
/** Array of child schemas */
200
childSchemas: { schema: Schema, model: any }[];
201
202
/** Object containing discriminators */
203
discriminators?: { [name: string]: Schema };
204
205
/** Original object passed to constructor */
206
obj: SchemaDefinition<T>;
207
208
/** All paths and their types */
209
paths: { [key: string]: SchemaType };
210
}
211
```
212
213
**Usage Examples:**
214
215
```javascript
216
const mongoose = require('mongoose');
217
const { Schema } = mongoose;
218
219
// Basic schema creation
220
const blogSchema = new Schema({
221
title: String,
222
content: String,
223
author: { type: Schema.Types.ObjectId, ref: 'User' },
224
tags: [String],
225
createdAt: { type: Date, default: Date.now }
226
});
227
228
// Add fields after creation
229
blogSchema.add({
230
publishedAt: Date,
231
views: { type: Number, default: 0 }
232
});
233
234
// Create virtual properties
235
blogSchema.virtual('url').get(function() {
236
return `/blog/${this._id}`;
237
});
238
239
// Add instance methods
240
blogSchema.method('incrementViews', function() {
241
this.views += 1;
242
return this.save();
243
});
244
245
// Add static methods
246
blogSchema.static('findByAuthor', function(authorId) {
247
return this.find({ author: authorId });
248
});
249
250
// Add middleware
251
blogSchema.pre('save', function() {
252
if (this.isModified('content')) {
253
this.publishedAt = new Date();
254
}
255
});
256
```
257
258
### Schema Types
259
260
Built-in schema types for defining field types with validation and casting.
261
262
```javascript { .api }
263
// Built-in schema types
264
Schema.Types.String: StringSchemaType;
265
Schema.Types.Number: NumberSchemaType;
266
Schema.Types.Date: DateSchemaType;
267
Schema.Types.Boolean: BooleanSchemaType;
268
Schema.Types.ObjectId: ObjectIdSchemaType;
269
Schema.Types.Array: ArraySchemaType;
270
Schema.Types.Buffer: BufferSchemaType;
271
Schema.Types.Mixed: MixedSchemaType;
272
Schema.Types.Decimal128: Decimal128SchemaType;
273
Schema.Types.Map: MapSchemaType;
274
Schema.Types.UUID: UUIDSchemaType;
275
Schema.Types.BigInt: BigIntSchemaType;
276
Schema.Types.Subdocument: SubdocumentSchemaType;
277
Schema.Types.Int32: Int32SchemaType;
278
Schema.Types.Double: DoubleSchemaType;
279
280
// SchemaType base methods
281
interface SchemaType {
282
/** Set as required field */
283
required(required?: boolean | Function, message?: string): this;
284
285
/** Set default value */
286
default(val: any): this;
287
288
/** Set field selection */
289
select(val: boolean): this;
290
291
/** Validate field value */
292
validate(validator: Function | RegExp, message?: string): this;
293
294
/** Set getter transformation */
295
get(fn: Function): this;
296
297
/** Set setter transformation */
298
set(fn: Function): this;
299
300
/** Create index on field */
301
index(options?: any): this;
302
303
/** Create unique index */
304
unique(val?: boolean): this;
305
306
/** Create sparse index */
307
sparse(val?: boolean): this;
308
}
309
```
310
311
### String Schema Type
312
313
String-specific schema type with string validation and transformation methods.
314
315
```javascript { .api }
316
interface StringSchemaType extends SchemaType {
317
/** Convert to lowercase */
318
lowercase(val?: boolean): this;
319
320
/** Convert to uppercase */
321
uppercase(val?: boolean): this;
322
323
/** Trim whitespace */
324
trim(val?: boolean): this;
325
326
/** Validate against regex pattern */
327
match(regex: RegExp, message?: string): this;
328
329
/** Validate against enumerated values */
330
enum(values: string[] | { values: string[], message?: string }): this;
331
332
/** Minimum string length */
333
minlength(length: number, message?: string): this;
334
335
/** Maximum string length */
336
maxlength(length: number, message?: string): this;
337
}
338
```
339
340
### Number Schema Type
341
342
Number-specific schema type with numeric validation methods.
343
344
```javascript { .api }
345
interface NumberSchemaType extends SchemaType {
346
/** Minimum value */
347
min(value: number, message?: string): this;
348
349
/** Maximum value */
350
max(value: number, message?: string): this;
351
352
/** Validate against enumerated values */
353
enum(values: number[] | { values: number[], message?: string }): this;
354
}
355
```
356
357
### Date Schema Type
358
359
Date-specific schema type with date validation and TTL support.
360
361
```javascript { .api }
362
interface DateSchemaType extends SchemaType {
363
/** Minimum date */
364
min(value: Date, message?: string): this;
365
366
/** Maximum date */
367
max(value: Date, message?: string): this;
368
369
/** Set TTL expiration */
370
expires(seconds: number | string): this;
371
}
372
```
373
374
### ObjectId Schema Type
375
376
ObjectId-specific schema type with reference support for population.
377
378
```javascript { .api }
379
interface ObjectIdSchemaType extends SchemaType {
380
/** Reference to another model */
381
ref(model: string | Model<any>): this;
382
383
/** Reference function for dynamic refs */
384
refPath(path: string): this;
385
386
/** Auto-generate ObjectId */
387
auto(val?: boolean): this;
388
}
389
```
390
391
### Array Schema Type
392
393
Array schema type for defining arrays of values with element validation.
394
395
```javascript { .api }
396
interface ArraySchemaType extends SchemaType {
397
/** Validate array of specific type */
398
of(schemaType: SchemaType): this;
399
400
/** Validate array of ObjectIds with reference */
401
ref(model: string): this;
402
}
403
404
// Array field usage examples
405
const schema = new Schema({
406
tags: [String], // Array of strings
407
scores: [{ type: Number, min: 0, max: 100 }], // Array of numbers with validation
408
authors: [{ type: Schema.Types.ObjectId, ref: 'User' }], // Array of references
409
metadata: [Schema.Types.Mixed], // Array of mixed types
410
comments: [{ // Array of subdocuments
411
text: String,
412
author: String,
413
createdAt: { type: Date, default: Date.now }
414
}]
415
});
416
```
417
418
### Virtual Properties
419
420
Create computed properties that don't persist to MongoDB but are available on documents.
421
422
```javascript { .api }
423
interface VirtualType {
424
/** Define getter function */
425
get(fn: Function): this;
426
427
/** Define setter function */
428
set(fn: Function): this;
429
430
/** Set virtual options */
431
options(opts: any): this;
432
}
433
```
434
435
**Usage Examples:**
436
437
```javascript
438
// Virtual property with getter only
439
userSchema.virtual('fullName').get(function() {
440
return `${this.firstName} ${this.lastName}`;
441
});
442
443
// Virtual property with getter and setter
444
userSchema.virtual('fullName')
445
.get(function() {
446
return `${this.firstName} ${this.lastName}`;
447
})
448
.set(function(name) {
449
const parts = name.split(' ');
450
this.firstName = parts[0];
451
this.lastName = parts[1];
452
});
453
454
// Virtual populate (for reverse relationships)
455
userSchema.virtual('posts', {
456
ref: 'Post',
457
localField: '_id',
458
foreignField: 'author'
459
});
460
```
461
462
### Middleware (Hooks)
463
464
Pre and post middleware for intercepting document and model operations.
465
466
```javascript { .api }
467
// Pre middleware - runs before the operation
468
schema.pre('save', function(next) {
469
// 'this' refers to the document
470
this.modifiedAt = new Date();
471
next();
472
});
473
474
// Pre middleware with async/await
475
schema.pre('save', async function() {
476
// Async operations
477
await this.populate('author');
478
});
479
480
// Post middleware - runs after the operation
481
schema.post('save', function(doc, next) {
482
console.log('Document saved:', doc._id);
483
next();
484
});
485
486
// Post middleware for error handling
487
schema.post('save', function(error, doc, next) {
488
if (error.name === 'MongoError' && error.code === 11000) {
489
next(new Error('Duplicate key error'));
490
} else {
491
next(error);
492
}
493
});
494
495
// Available middleware hooks
496
'init', 'validate', 'save', 'remove', 'deleteOne', 'deleteMany',
497
'updateOne', 'updateMany', 'findOneAndDelete', 'findOneAndUpdate',
498
'insertMany', 'aggregate'
499
```
500
501
## Types
502
503
```javascript { .api }
504
interface SchemaOptions {
505
/** Auto-create indexes */
506
autoIndex?: boolean;
507
508
/** Auto-create collection */
509
autoCreate?: boolean;
510
511
/** Buffer commands when disconnected */
512
bufferCommands?: boolean;
513
514
/** Capped collection options */
515
capped?: boolean | number | { size?: number; max?: number; };
516
517
/** Collection name */
518
collection?: string;
519
520
/** Discriminator key field name */
521
discriminatorKey?: string;
522
523
/** Include virtual 'id' field */
524
id?: boolean;
525
526
/** Include '_id' field */
527
_id?: boolean;
528
529
/** Minimize empty objects */
530
minimize?: boolean;
531
532
/** Read preference */
533
read?: string;
534
535
/** Write concern */
536
writeConcern?: any;
537
538
/** Shard key */
539
shardKey?: any;
540
541
/** Strict mode for schema */
542
strict?: boolean | 'throw';
543
544
/** Strict mode for queries */
545
strictQuery?: boolean | 'throw';
546
547
/** toJSON transform options */
548
toJSON?: ToObjectOptions;
549
550
/** toObject transform options */
551
toObject?: ToObjectOptions;
552
553
/** Type key for discriminators */
554
typeKey?: string;
555
556
/** Validate before save */
557
validateBeforeSave?: boolean;
558
559
/** Version key field name */
560
versionKey?: string | boolean;
561
562
/** Automatic timestamps */
563
timestamps?: boolean | SchemaTimestampsConfig;
564
565
/** Skip version increment */
566
skipVersioning?: any;
567
568
/** Use nested strict mode */
569
useNestedStrict?: boolean;
570
}
571
572
interface SchemaTimestampsConfig {
573
/** Created at field name */
574
createdAt?: boolean | string;
575
576
/** Updated at field name */
577
updatedAt?: boolean | string;
578
579
/** Function to get current time */
580
currentTime?: () => Date;
581
}
582
583
interface ToObjectOptions {
584
/** Include getters */
585
getters?: boolean;
586
587
/** Include virtuals */
588
virtuals?: boolean;
589
590
/** Minimize empty objects */
591
minimize?: boolean;
592
593
/** Transform function */
594
transform?: Function;
595
596
/** Depopulate populated fields */
597
depopulate?: boolean;
598
599
/** Include version key */
600
versionKey?: boolean;
601
602
/** Return POJO instead of document */
603
flattenMaps?: boolean;
604
}
605
606
type SchemaDefinition<T> = {
607
[K in keyof T]?: SchemaTypeOptions<T[K]> | Schema | SchemaType;
608
};
609
610
interface SchemaTypeOptions<T> {
611
type?: any;
612
required?: boolean | [boolean, string] | Function;
613
default?: T | Function;
614
select?: boolean;
615
validate?: Function | RegExp | [Function, string] | [RegExp, string];
616
get?: Function;
617
set?: Function;
618
alias?: string;
619
index?: boolean | any;
620
unique?: boolean;
621
sparse?: boolean;
622
ref?: string | Model<any> | Function;
623
refPath?: string;
624
// String-specific options
625
lowercase?: boolean;
626
uppercase?: boolean;
627
trim?: boolean;
628
match?: RegExp | [RegExp, string];
629
enum?: T[] | { values: T[], message?: string };
630
minlength?: number | [number, string];
631
maxlength?: number | [number, string];
632
// Number-specific options
633
min?: number | [number, string];
634
max?: number | [number, string];
635
// Date-specific options
636
expires?: number | string;
637
// Array-specific options
638
of?: SchemaTypeOptions<any>;
639
}
640
641
interface SearchIndexDescription {
642
/** Index name */
643
name?: string;
644
645
/** Index definition */
646
definition?: any;
647
648
/** Index type */
649
type?: string;
650
}
651
```