Nest 无法解析依赖关系:使用猫鼬包的多个数据库连接



嗨,我正试图使用带有命名连接的mongose nestjs包建立多个数据库连接,并遵循此处的文档(https://docs.nestjs.com/techniques/mongodb#multiple-数据库(:但我在启动时遇到运行时错误:

错误:Nest无法解析RetailLocationModelModel(?(的依赖项。请确保索引[0]处的参数partnersConnection在MongooseModule上下文中可用

只有当我使用命名连接时才会发生这种情况。如果我从forFeature参数中删除连接名称"partners"(即使将其保持在forRootAsync(,它也可以正常工作。可能是因为模型连接到默认连接,而且只有一个,所以它会自动与"合作伙伴"连接。

// dependencies
"@nestjs/axios": "^0.0.8",
"@nestjs/common": "^8.4.5",
"@nestjs/config": "^1.0.1",
"@nestjs/core": "^8.4.5",
"@nestjs/mongoose": "^8.0.1",
@Module({
imports: [DatabaseModule, RetailPartnersModule],
})
export class AppModule {}
@Module({
imports: [ConfigModule, MongooseModule.forRootAsync(B2CPartnersDbAsyncOptions)],
providers: [DatabaseService],
exports: [DatabaseService],
})
export class DatabaseModule {}
export const B2CPartnersDbAsyncOptions = {
imports: [ConfigModule],
useFactory: (configService: ConfigService) => {
const user = configService.get<string>(MONGODB_USERNAME)
const password = configService.get<string>(MONGODB_PASSWORD)
const database = configService.get<string>('b2c_partners_acc')
const host = configService.get<string>(MONGODB_URL)
const uri = `mongodb+srv://${user}:${password}@${host}/${database}`
return {
uri,
useNewUrlParser: true,
useUnifiedTopology: true,
connectionName: 'partners',
}
},
inject: [ConfigService],
}
@Module({
imports: [
MongooseModule.forFeature(
[{ name: RetailLocationModel.name, schema: RetailLocationSchema }],
'partners'
),
],
controllers: [RetailPartnersController],
providers: [RetailPartnersService, RetailLocationsRepository],
})
export class RetailPartnersModule {}
export class RetailLocationsRepository {
constructor(
@InjectModel(RetailLocationModel.name) private model: Model<RetailLocationDocument>
) {}
}

请注意,我不能在InjectModel中添加"partners"作为第二个参数,因为TS抱怨它只需要1个参数(尽管官方文档说我可以将连接名称作为额外参数传递(。当手动更新打字法以支持2个参数时,我仍然会收到未解析依赖项的相同运行时错误

更新:

当我进入包提供的mongoose模块并记录RootAsync和forFeature的静态方法的结果时,forRootAsync不提供partnersConnection令牌,其中forFeature试图将其注入

// Mongoose.module.ts
class MongooseModule {
static forRootAsync(options) {
return {
module: MongooseModule_1,
imports: [mongoose_core_module_1.MongooseCoreModule.forRootAsync(options)],
};
}
}

其中,RootAsync.inports[0]的日志记录。providers产生:

{
provide: 'MongooseModuleOptions',
useFactory: [Function (anonymous)],
inject: [ [class ConfigService] ]
},
{
provide: 'DatabaseConnection',
useFactory: [Function: useFactory],
inject: [ 'MongooseModuleOptions' ]
},
{ provide: 'MongooseConnectionName', useValue: 'DatabaseConnection' }

与forFeature:

static forFeature(models = [], connectionName) {
const providers = mongoose_providers_1.createMongooseProviders(connectionName, models);
const result =
{
module: MongooseModule_1,
providers: providers,
exports: providers,
};
console.log('result forFeature1: ', result.providers)
return result;
}

日志到:

[{
provide: 'RetailLocationModelModel',
useFactory: [Function: useFactory],
inject: [ 'partnersConnection' ]
}]

因此,在forRootAsync静态函数中似乎没有正确设置partnersConnection令牌,因为连接被命名为默认值"DatabaseConnection">

我通过将RetailLocationsModule的connectionName更改为"Database"来验证这一点,运行时错误得到了解决。

@Module({
imports: [
MongooseModule.forFeature(
[{ name: RetailLocationModel.name, schema: RetailLocationSchema }],
'Database'
),
],
controllers: [RetailPartnersController],
providers: [RetailPartnersService, RetailLocationsRepository],
})
export class RetailPartnersModule {}

因此,forRootAsync中要么有一个错误,要么我缺少了一些东西。

不向工厂提供connectionName,而是将其提供给MongooseAncOptions:的选项对象

export function createDbConfig(
dbName: string
): (configService: ConfigService) => MongooseModuleAsyncOptions {
return (configService: ConfigService): MongooseModuleOptions => {
const logger = new Logger(createDbConfig.name)
const user = configService.get<string>(MONGODB_USERNAME, '')
const password = configService.get<string>(MONGODB_PASSWORD, '')
const database = configService.get<string>(dbName, '')
const host = configService.get<string>(MONGODB_URL, '')
const mongoProtocol =
configService.get<string>(NODE_ENV) === 'local' ? Protocols.local : Protocols.production
const uri = `${mongoProtocol}://${user}:${password}@${host}/${database}`
logger.verbose(`Connecting to the Mongo database URI: ${uri}`)
return {
uri,
useNewUrlParser: true,
useUnifiedTopology: true,
retryAttempts: 0,
// connectionName: 'partners' <= remove from here
}
}
}
export const B2CPartnersDbAsyncOptions: MongooseModuleAsyncOptions = {
imports: [ConfigModule],
useFactory: createDbConfig(DB_NAME.default),
inject: [ConfigService],
connectionName: 'partners', // <= put it here instead
}

然后在使用@InjectConnection的模块中,提供连接的名称("伙伴"(,以及每个MongooseModule.forFeature,例如

@Injectable()
export class DatabaseService {
constructor(@InjectConnection('partners') private _connection: Connection) {}
public getStatus(): DatabaseHealthStatus {
return this._connection && this._connection.readyState === 1
? DatabaseHealthStatus.CONNECTED
: DatabaseHealthStatus.DISCONNECTED
}
public get connection(): Connection {
return this._connection
}
}
@Module({
imports: [
MongooseModule.forFeature(
[{ name: RetailLocationModel.name, schema: RetailLocationSchema }],
'partners'
),
],
controllers: [RetailPartnersController],
providers: [RetailPartnersService, RetailLocationsRepository],
})
export class RetailPartnersModule {}

最新更新