0
# Schema Factories
1
2
Factory classes for generating Mongoose schemas and definitions from decorated TypeScript classes. The factory system transforms class-based schema definitions into proper Mongoose schemas with all decorators processed.
3
4
## Capabilities
5
6
### SchemaFactory
7
8
Creates complete Mongoose schemas from decorated TypeScript classes.
9
10
```typescript { .api }
11
class SchemaFactory {
12
/**
13
* Creates a Mongoose schema from a decorated TypeScript class
14
* @param target - The decorated class constructor
15
* @returns Mongoose schema instance
16
*/
17
static createForClass<TClass>(target: Type<TClass>): mongoose.Schema<TClass>;
18
}
19
```
20
21
**Usage Examples:**
22
23
```typescript
24
import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose';
25
26
// Define schema class
27
@Schema()
28
export class User {
29
@Prop({ required: true })
30
name: string;
31
32
@Prop({ unique: true })
33
email: string;
34
35
@Prop({ default: Date.now })
36
createdAt: Date;
37
}
38
39
// Generate Mongoose schema
40
export const UserSchema = SchemaFactory.createForClass(User);
41
42
// Use in module registration
43
@Module({
44
imports: [
45
MongooseModule.forFeature([
46
{ name: User.name, schema: UserSchema }
47
])
48
],
49
})
50
export class UserModule {}
51
52
// Schema with complex properties
53
@Schema({
54
timestamps: true,
55
collection: 'products'
56
})
57
export class Product {
58
@Prop({ required: true, index: true })
59
name: string;
60
61
@Prop({ required: true, min: 0 })
62
price: number;
63
64
@Prop([String])
65
tags: string[];
66
67
@Prop({
68
type: {
69
street: String,
70
city: String,
71
country: { type: String, default: 'US' }
72
}
73
})
74
address: {
75
street: string;
76
city: string;
77
country: string;
78
};
79
80
@Virtual()
81
get displayPrice(): string {
82
return `$${this.price.toFixed(2)}`;
83
}
84
}
85
86
export const ProductSchema = SchemaFactory.createForClass(Product);
87
88
// Schema with references
89
@Schema()
90
export class Order {
91
@Prop({ type: mongoose.Types.ObjectId, ref: 'User', required: true })
92
user: mongoose.Types.ObjectId;
93
94
@Prop([{
95
product: { type: mongoose.Types.ObjectId, ref: 'Product', required: true },
96
quantity: { type: Number, required: true, min: 1 },
97
price: { type: Number, required: true }
98
}])
99
items: {
100
product: mongoose.Types.ObjectId;
101
quantity: number;
102
price: number;
103
}[];
104
105
@Prop({ enum: ['pending', 'processing', 'shipped', 'delivered'] })
106
status: string;
107
108
@Virtual()
109
get totalAmount(): number {
110
return this.items.reduce((sum, item) => sum + (item.price * item.quantity), 0);
111
}
112
}
113
114
export const OrderSchema = SchemaFactory.createForClass(Order);
115
```
116
117
### DefinitionsFactory
118
119
Creates Mongoose schema definitions (plain objects) from decorated classes for advanced schema customization.
120
121
```typescript { .api }
122
class DefinitionsFactory {
123
/**
124
* Creates a Mongoose schema definition from a decorated TypeScript class
125
* @param target - The decorated class constructor
126
* @returns Mongoose schema definition object
127
*/
128
static createForClass(target: Type<unknown>): mongoose.SchemaDefinition;
129
}
130
```
131
132
**Usage Examples:**
133
134
```typescript
135
import { DefinitionsFactory } from '@nestjs/mongoose';
136
137
@Schema()
138
export class BaseDocument {
139
@Prop({ required: true })
140
name: string;
141
142
@Prop({ default: Date.now })
143
createdAt: Date;
144
}
145
146
// Get schema definition for customization
147
const baseDefinition = DefinitionsFactory.createForClass(BaseDocument);
148
149
// Create custom schema with definition
150
const customSchema = new mongoose.Schema({
151
...baseDefinition,
152
// Add additional fields
153
customField: { type: String, default: 'custom-value' },
154
// Override existing fields
155
name: { type: String, required: true, uppercase: true },
156
}, {
157
timestamps: true,
158
collection: 'custom_documents'
159
});
160
161
// Use with discriminators
162
const AnimalSchema = SchemaFactory.createForClass(Animal);
163
const DogSchema = new mongoose.Schema(DefinitionsFactory.createForClass(Dog));
164
const CatSchema = new mongoose.Schema(DefinitionsFactory.createForClass(Cat));
165
166
AnimalSchema.discriminator('Dog', DogSchema);
167
AnimalSchema.discriminator('Cat', CatSchema);
168
```
169
170
### VirtualsFactory
171
172
Processes virtual properties and adds them to existing schemas.
173
174
```typescript { .api }
175
class VirtualsFactory {
176
/**
177
* Inspects a class for virtual properties and adds them to a schema
178
* @param target - The decorated class constructor
179
* @param schema - The Mongoose schema to add virtuals to
180
*/
181
static inspect<TClass>(target: Type<TClass>, schema: mongoose.Schema<TClass>): void;
182
}
183
```
184
185
**Usage Examples:**
186
187
```typescript
188
import { VirtualsFactory } from '@nestjs/mongoose';
189
190
@Schema()
191
export class User {
192
@Prop({ required: true })
193
firstName: string;
194
195
@Prop({ required: true })
196
lastName: string;
197
198
@Prop()
199
email: string;
200
201
@Virtual()
202
get fullName(): string {
203
return `${this.firstName} ${this.lastName}`;
204
}
205
206
@Virtual({
207
options: {
208
ref: 'Post',
209
localField: '_id',
210
foreignField: 'author'
211
}
212
})
213
posts: any[];
214
}
215
216
// Create schema without virtuals first
217
const userSchema = new mongoose.Schema({
218
firstName: { type: String, required: true },
219
lastName: { type: String, required: true },
220
email: String,
221
});
222
223
// Add virtuals from decorated class
224
VirtualsFactory.inspect(User, userSchema);
225
226
// Schema now includes virtual properties
227
export const UserSchema = userSchema;
228
```
229
230
## Advanced Factory Usage
231
232
### Custom Schema Creation Pipeline
233
234
```typescript
235
import { SchemaFactory, DefinitionsFactory, VirtualsFactory } from '@nestjs/mongoose';
236
237
export class CustomSchemaFactory {
238
static createAdvancedSchema<T>(target: Type<T>, options?: any): mongoose.Schema<T> {
239
// Get base definition
240
const definition = DefinitionsFactory.createForClass(target);
241
242
// Create schema with custom options
243
const schema = new mongoose.Schema(definition, {
244
timestamps: true,
245
versionKey: false,
246
...options,
247
});
248
249
// Add virtuals
250
VirtualsFactory.inspect(target, schema);
251
252
// Add custom middleware
253
schema.pre('save', function() {
254
if (this.isNew) {
255
this.createdAt = new Date();
256
}
257
});
258
259
// Add custom methods
260
schema.methods.toJSON = function() {
261
const obj = this.toObject();
262
delete obj.__v;
263
return obj;
264
};
265
266
return schema;
267
}
268
}
269
270
// Usage
271
@Schema()
272
export class CustomDocument {
273
@Prop({ required: true })
274
title: string;
275
276
@Virtual()
277
get slug(): string {
278
return this.title.toLowerCase().replace(/\s+/g, '-');
279
}
280
}
281
282
export const CustomDocumentSchema = CustomSchemaFactory.createAdvancedSchema(
283
CustomDocument,
284
{ collection: 'custom_docs' }
285
);
286
```
287
288
### Schema Composition
289
290
```typescript
291
// Base schema components
292
@Schema()
293
export class Timestamped {
294
@Prop({ default: Date.now })
295
createdAt: Date;
296
297
@Prop({ default: Date.now })
298
updatedAt: Date;
299
}
300
301
@Schema()
302
export class SoftDeleted {
303
@Prop({ default: false })
304
isDeleted: boolean;
305
306
@Prop()
307
deletedAt: Date;
308
}
309
310
// Composed schema
311
@Schema()
312
export class BlogPost extends Timestamped {
313
@Prop({ required: true })
314
title: string;
315
316
@Prop({ required: true })
317
content: string;
318
319
@Prop([String])
320
tags: string[];
321
322
@Virtual()
323
get excerpt(): string {
324
return this.content.substring(0, 150) + '...';
325
}
326
}
327
328
// Create with multiple inheritance patterns
329
export function createComposedSchema<T>(
330
target: Type<T>,
331
mixins: Type<any>[] = []
332
): mongoose.Schema<T> {
333
const baseDefinition = DefinitionsFactory.createForClass(target);
334
335
// Merge definitions from mixins
336
const composedDefinition = mixins.reduce((def, mixin) => {
337
const mixinDef = DefinitionsFactory.createForClass(mixin);
338
return { ...def, ...mixinDef };
339
}, baseDefinition);
340
341
const schema = new mongoose.Schema(composedDefinition);
342
343
// Add virtuals from all classes
344
[target, ...mixins].forEach(cls => {
345
VirtualsFactory.inspect(cls, schema);
346
});
347
348
return schema;
349
}
350
351
// Usage
352
export const BlogPostSchema = createComposedSchema(BlogPost, [Timestamped, SoftDeleted]);
353
```
354
355
## Provider Functions
356
357
Internal functions used by the module system to create NestJS providers.
358
359
### createMongooseProviders
360
361
Creates NestJS providers for synchronous model registration.
362
363
```typescript { .api }
364
/**
365
* Creates NestJS providers for synchronous models
366
* @param connectionName - Optional connection name
367
* @param options - Array of model definitions
368
* @returns Array of NestJS providers
369
*/
370
function createMongooseProviders(
371
connectionName?: string,
372
options?: ModelDefinition[]
373
): Provider[];
374
```
375
376
### createMongooseAsyncProviders
377
378
Creates NestJS providers for asynchronous model registration.
379
380
```typescript { .api }
381
/**
382
* Creates NestJS providers for asynchronous models
383
* @param connectionName - Optional connection name
384
* @param modelFactories - Array of async model factories
385
* @returns Array of NestJS providers
386
*/
387
function createMongooseAsyncProviders(
388
connectionName?: string,
389
modelFactories?: AsyncModelFactory[]
390
): Provider[];
391
```
392
393
## Type Metadata Storage
394
395
Advanced internal system for storing and retrieving decorator metadata.
396
397
```typescript { .api }
398
class TypeMetadataStorage {
399
/**
400
* Add property metadata from @Prop decorators
401
* @param metadata - Property metadata object
402
*/
403
addPropertyMetadata(metadata: PropertyMetadata): void;
404
405
/**
406
* Add schema metadata from @Schema decorators
407
* @param metadata - Schema metadata object
408
*/
409
addSchemaMetadata(metadata: SchemaMetadata): void;
410
411
/**
412
* Add virtual metadata from @Virtual decorators
413
* @param metadata - Virtual metadata object
414
*/
415
addVirtualMetadata(metadata: VirtualMetadataInterface): void;
416
417
/**
418
* Get schema metadata for a target class
419
* @param target - Class constructor
420
* @returns Schema metadata or undefined
421
*/
422
getSchemaMetadataByTarget(target: Type<unknown>): SchemaMetadata | undefined;
423
424
/**
425
* Get virtual metadata for a target class
426
* @param targetFilter - Class constructor to filter by
427
* @returns Array of virtual metadata
428
*/
429
getVirtualsMetadataByTarget<TClass>(targetFilter: Type<TClass>): VirtualMetadataInterface[];
430
}
431
```