NestJS实现动态模型:根据年份参数匹配对应集合
If you’re working with MongoDB (the most common use case for "collections" in NestJS), here’s a straightforward way to implement dynamic models based on a year parameter:
1. Define a Reusable Base Schema
First, create a schema that matches the structure of documents across all your year-prefixed collections (e.g., 2020-foo, 2021-foo):
// foo.schema.ts import { Schema } from 'mongoose'; export const FooSchema = new Schema({ // Add your document fields here name: String, value: Number, createdAt: { type: Date, default: Date.now }, }); // Optional: Define a type for type safety export interface FooDocument extends Document { name: string; value: number; createdAt: Date; }
2. Build a Dynamic Model Service
Create a service that generates the correct Mongoose model on demand using the year parameter. This leverages NestJS’s database connection to avoid duplicate model registrations:
// dynamic-foo.service.ts import { Injectable, Inject } from '@nestjs/common'; import { Connection, Model } from 'mongoose'; import { FooSchema, FooDocument } from './foo.schema'; @Injectable() export class DynamicFooService { constructor(@Inject('DATABASE_CONNECTION') private readonly connection: Connection) {} getFooModel(year: number): Model<FooDocument> { const collectionName = `${year}-foo`; // Reuse existing model if it's already registered if (this.connection.models[collectionName]) { return this.connection.models[collectionName] as Model<FooDocument>; } // Create and return a new model for the target collection return this.connection.model<FooDocument>(collectionName, FooSchema); } }
3. Register the Database Connection
In your root module (e.g., AppModule), set up the Mongoose connection and make the dynamic service available:
// app.module.ts import { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; import { DynamicFooService } from './dynamic-foo.service'; import { FooController } from './foo.controller'; @Module({ imports: [ MongooseModule.forRoot('mongodb://localhost:27017/your-db-name'), ], providers: [DynamicFooService], controllers: [FooController], }) export class AppModule {}
4. Use the Dynamic Model in a Controller
Inject the service into your controller, validate the year parameter, and fetch the correct model to run database operations:
// foo.controller.ts import { Controller, Get, Param, BadRequestException } from '@nestjs/common'; import { DynamicFooService } from './dynamic-foo.service'; @Controller('foo') export class FooController { constructor(private readonly dynamicFooService: DynamicFooService) {} @Get(':year') async getFooData(@Param('year') yearStr: string) { const year = parseInt(yearStr, 10); if (isNaN(year) || year < 2000 || year > new Date().getFullYear()) { throw new BadRequestException('Invalid year parameter'); } const fooModel = this.dynamicFooService.getFooModel(year); return fooModel.find().exec(); } }
Key Tips
- Model Caching: The service checks for existing models to avoid Mongoose errors from redefining the same model multiple times.
- Validation: Always validate the year input to prevent invalid collection names or unexpected behavior.
- TypeORM Alternative: If using SQL with TypeORM, replace the model logic with
EntityManager.getRepository()using the dynamic table name (e.g.,${year}_foo).
内容的提问来源于stack exchange,提问作者mohamed ouf

