NestJs - mongoose -动态集合命名

zbdgwd5y  于 2022-11-13  发布在  Go
关注(0)|答案(2)|浏览(202)

我想使用基于当前年份的动态集合名称。
例如:从“产品”到“产品2020”。
使用NESTJS,我必须导入具有特定集合名称的“module.forFeature”。

import { Module } from '@nestjs/common'
import { MongooseModule } from '@nestjs/mongoose'

@Module({
  imports: [
    MongooseModule.forFeature([
      {
        name: 'Products',
        schema: ProductsSchema
      }
    ])
  ],
  controllers: [ProductsController],
  providers: [ProductsService]
})

服务时的注入也是如此:

import { Injectable } from '@nestjs/common'
import { InjectModel } from '@nestjs/mongoose'

import { Model } from 'mongoose'

@Injectable()
export class ProductsService {
  constructor(
    @InjectModel('Products')
    private readonly productsModel: Model<Products>
  ) {}
}

最后,这是我的模式:

import { Schema } from 'mongoose'

export const ProductsSchema = new Schema(
  {
    _id: { Type: String, required: true },
    code: String
  },
  {
    collection: 'Products'
  }
)

是否有某种方法可以实现动态命名?
多谢了!

q5iwbnjs

q5iwbnjs1#

我偶然发现了一个类似的问题,我解决的方法是使用MongooseModule.forFeatureAsync方法。模型和模式声明与nestjs文档中的相同。

@Module({
  imports: [
    MongooseModule.forFeatureAsync([
      {
        name: UsersModel.name,
        imports: [EnvironmentModule],
        inject: [EnvironmentService],
        useFactory: (envService: EnvironmentService) => {
          const env = envService.getEnv();
          const schema = UsersSchema.set(
            'collection',
            `${env.countryCode}-users`,
          );
          return schema;
        },
      },
    ]),
    ...
  ],
  providers: []
  ...
r8xiu3jd

r8xiu3jd2#

我一直在寻找解决这类问题的方法,但我遇到了一堵墙,没有明确的方法来做这件事。
以下(最少)代码示例化服务,每个服务根据country parameter绑定到特定模型。即,ServiceX绑定到数据库X的模型,ServiceY绑定到数据库Y中的相同模型
但这里是我设法做到的。你绝对可以做一个工作来满足你的需要
首先是模型/接口。通常用于不同服务之间

export interface User extends Document {
    readonly username: string;
    readonly password: string;
}

export const UserSchema = new mongoose.Schema(
    {
        _id: mongoose.ObjectId,
        username: String,
        password: String
    },
    { collection: 'accounts', autoCreate: true }
);

对于不同数据库/集合中的每个模型,服务定义实际上是相同的

@Injectable()
export class XUserService implements OnModuleInit{
    constructor(
        private userModel: Model<User>,
    ) {
    }

    ////////////////////////////////////////////////////////////////////////////
    async onModuleInit(): Promise<any> {
        console.log(`inside service dbname=: ${this.userModel.db.name} > ${this.userModel.collection.collectionName}` );
        // await new this.userModel({_id: mongoose.Types.ObjectId(), username: 'test', password: 'test', flag: this.c}).save()
    }

    async insert(){
        console.log(`inside service dbname=: ${this.userModel.db.name} > ${this.userModel.collection.collectionName}` );
        await new this.userModel({
            _id: mongoose.Types.ObjectId(),
            username: this.userModel.db.name,
            password: '0000'
        }).save();
    }

    async findOne(): Promise<User>{
        console.log(`inside service in : ${this.userModel.db.name} > ${this.userModel.collection.collectionName}` );
        return this.userModel.findOne()
    }
}

对于模块,我创建了一个DynamicModule

  • 导入数据库连接
  • 为每个需求创建一个模型,(对于我的情况,每个数据库中有一个模型)
  • 创建每个Model并将其绑定到一个Service,这样服务的示例化将是正确的
@Module({

})
export class XUserModule{
    static register( /*use can pass parameter here*/): DynamicModule{
        return{
            module: XUserModule,
            imports: [
                DatabaseModule
            ],
            controllers: [
                XUserController
            ],
            providers: [
                // Create Models here, #1 and #2 in two different database
                {
                    provide: 'dz-'+'UserModel',
                    useFactory: (connection: Connection)=> {
                        return connection.model('User', UserSchema )
                    },
                    inject: [ dbname.shooffood('dz')+'Connection' ]
                },{
                    provide: 'ca-'+'UserModel',
                    useFactory: (connection: Connection)=> {
                        return connection.model('User', UserSchema )
                    },
                    inject: [ dbname.shooffood('ca')+'Connection' ]
                },

   
                // Create Providers/Services for each Model and Inject the Model to the Service by `TokenString`
                {
                    provide: 'dz' + XUserService.name,
                    useFactory: (m: any)=> {
                        console.log(m);
                        return new XUserService(m);
                    },
                    inject: [ 'dz-'+'UserModel' ]
                },{
                    provide: 'ca' + XUserService.name,
                    useFactory: (m: any)=> {
                        console.log(m);
                        return new XUserService(m);
                    },
                    inject: [ 'ca-'+'UserModel' ]
                }
            ],

            // Export your service with the same `provide` name for later usage.
            exports: [
                'dz' + XUserService.name,
                'ca' + XUserService.name
            ]
        }
    }
}

仅供参考,数据库模块看起来像常数dbname是连接名称,uri是连接字符串。

const databaseProviders = [
    {
        provide: dbname.admin+'Connection',
        useFactory: (): Promise<typeof mongoose> => mongoose.createConnection(uri.admin),
    },{
        provide: dbname.system+'Connection',
        useFactory: (): Promise<typeof mongoose> => mongoose.createConnection(uri.system),
    },{
        provide: dbname.shooffood('dz')+'Connection',
        useFactory: (): Promise<typeof mongoose> => mongoose.createConnection(uri.dzfood),
    },{
        provide: dbname.shooffood('ca')+'Connection',
        useFactory: (): Promise<typeof mongoose> => mongoose.createConnection(uri.cafood),
    }
];

@Module({
    providers: [
        ...databaseProviders
    ],
    exports: [
        dbname.admin+'Connection',
        dbname.system+'Connection',
        dbname.shooffood('dz')+'Connection',
        dbname.shooffood('ca')+'Connection'
    ]
})
export class DatabaseModule {}

至于控制器,只有一个通过请求参数:country处理每个服务。但首先我必须列出所有可能的模型和服务,以包括在应用程序中。

@Controller(':country')
export class XUserController {
    private byCountryServices = new Map();
    constructor(
        // Inject all required services by `tokenString`
        @Inject('dz' + XUserService.name) private dzUserService: XUserService,
        @Inject('ca' + XUserService.name) private caUserService: XUserService,
    ) {
        // Add to `<key, value>` Map for easy by param access
        this.byCountryServices.set('dz', this.dzUserService );
        this.byCountryServices.set('ca', this.caUserService );
    }

    @Get('post')
    async post(
        @Param('country') c: string
    ): Promise<string>{
        await this.byCountryServices.get(c).insert()
        return 'inserted in ' + c;
    }

    @Get('get')
    async get(
        @Param('country') c: string
    ): Promise<string>{
        console.log('param: ' + c)
        return await this.byCountryServices.get(c).findOne()
    }
}

最后,使用XUserModule.register()在AppModule中导入该模块

相关问题