Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When set connectionName to useClass, Populate Error: Schema hasn't been registered for model #1954

Closed
4 tasks done
virames-tr opened this issue Nov 15, 2023 · 1 comment
Closed
4 tasks done
Labels

Comments

@virames-tr
Copy link

virames-tr commented Nov 15, 2023

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

App Module

import { Module } from '@nestjs/common';
import { MasterModule } from './master/master.module';
import { CoreModule } from './core/core.module';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { MongooseModule } from '@nestjs/mongoose';
import { MasterConnection } from './config/master.connection';
import { ConnectionName } from './utils/connectionn.enum';
import { CoreConnection } from './config/core.connection';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    MongooseModule.forRootAsync({
      useClass: MasterConnection,
      connectionName: ConnectionName.MASTER,
    }),
    MongooseModule.forRootAsync({
      useClass: CoreConnection,
      connectionName: ConnectionName.CORE,
    }),
    MasterModule,
    CoreModule,
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

Master Config Service

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
  MongooseModuleOptions,
  MongooseOptionsFactory,
} from '@nestjs/mongoose';

@Injectable()
export class MasterConnection implements MongooseOptionsFactory {
  constructor(private configService: ConfigService) {}
  createMongooseOptions(): MongooseModuleOptions {
    return {
      uri: this.configService.getOrThrow('MONGODB_URI'),
      dbName: this.configService.getOrThrow('MASTER_DB'),
      connectionFactory(connection: any, name: any) {
        connection.plugin(require('mongoose-autopopulate'));
        return connection;
      },
    };
  }
}

Core Config Service

import { Inject, Injectable, NotFoundException, Scope } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
import {
  MongooseModuleOptions,
  MongooseOptionsFactory,
} from '@nestjs/mongoose';
import { TenantService } from 'src/master/tenant/services/tenant.service';

@Injectable({ scope: Scope.REQUEST })
export class CoreConnection implements MongooseOptionsFactory {
  constructor(
    private configService: ConfigService,
    private tenantService: TenantService,
    @Inject(REQUEST) private readonly request: Request,
  ) {}
  async createMongooseOptions(): Promise<MongooseModuleOptions> {
    const host = this.request.hostname.split('.');
    const tenant = await this.tenantService.find({ slug: host[0] });
    if (tenant) {
      return {
        uri: this.configService.getOrThrow('MONGODB_URI'),
        dbName: host[0],
        lazyConnection: true,
        connectionFactory(connection: any, name: any) {
          connection.plugin(require('mongoose-autopopulate'));
          return connection;
        },
      };
    } else {
      throw new NotFoundException('Tenant not found!');
    }
  }
}

Auth Module

import { Global, Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { User, UserSchema } from './entities/user.entity';
import { ConnectionName } from 'src/utils/connectionn.enum';
import { UserController } from './controllers/user.controller';
import { UserService } from './services/user.service';
import { AuthController } from './controllers/auth.controller';
import { JwtModule } from '@nestjs/jwt';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { Role, RoleSchema } from './entities/role.entity';
import { RoleService } from './services/role.service';
import { RoleController } from './controllers/role.controller';

@Global()
@Module({
  imports: [
    MongooseModule.forFeature(
      [
        { name: Role.name, schema: RoleSchema },
        { name: User.name, schema: UserSchema },
      ],
      ConnectionName.CORE,
    ),
    JwtModule.registerAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        global: true,
        secret: configService.getOrThrow('JWT_SECRET'),
        signOptions: {
          expiresIn: configService.getOrThrow('JWT_EXPIRES_IN'),
        },
      }),
      inject: [ConfigService],
    }),
  ],
  controllers: [AuthController, RoleController, UserController],
  providers: [RoleService, UserService],
  exports: [RoleService, UserService],
})
export class AuthModule {}

User Entity

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document, Schema as MongooseSchema } from 'mongoose';
import { Role } from './role.entity';

@Schema({
  versionKey: false,
  timestamps: {
    createdAt: 'created_at',
    updatedAt: 'updated_at',
  },
})
export class User extends Document {
  @Prop()
  username: string;

  @Prop()
  password: string;

  @Prop()
  email: string;

  @Prop()
  name: string;

  @Prop({
    type: [MongooseSchema.Types.ObjectId],
    ref: Role.name,
    autopopulate: true,
  })
  roles: Role[];
}

export const UserSchema = SchemaFactory.createForClass(User);

Minimum reproduction code

https://github.com/virames-tr/backend

Steps to reproduce

  1. npm i
  2. npm start:dev
  3. http://localhost:3000/api/v1/users
    ...see error

Expected behavior

I'm trying to set up a multi-tenant system. A different database will be used for each tenant. I shared my sample codes above. When I do it with useClass, the popuplate operation gives an error. If I connect with useFactory, this error does not occur. What could I be doing wrong or could this be a bug?

Package version

10.0.2

mongoose version

8.0.0

NestJS version

10.0.0

Node.js version

18.18.2

In which operating systems have you tested?

  • macOS
  • Windows
  • Linux

Other

No response

@virames-tr virames-tr added the bug label Nov 15, 2023
@kamilmysliwiec
Copy link
Member

Please, use our Discord channel (support) for such questions. We are using GitHub to track bugs, feature requests, and potential improvements.

@nestjs nestjs locked and limited conversation to collaborators Nov 16, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants