Imagine for example: I've got two databases with same objects/models but for different Organisations. And based on request I need to select correct DB to connect. I use this in app.module.ts
:
MongooseModule.forRootAsync({
imports: [HttpModule],
useClass: MyMongooseConfigService,
})
MyMongooseConfigService
looks something like this:
@Injectable({ scope: Scope.REQUEST })
export class MyMongooseConfigService implements MongooseOptionsFactory {
constructor(
@Inject(REQUEST)
private readonly req: Request,
private http: HttpService,
) {}
async createMongooseOptions(): Promise<MongooseModuleOptions> {
const param = req.headers.mysecretheader;
const foundDb = await this.http.get(`http://my-web-server/param/${param}`);
const dbName = foundDb.dbName;
const uri = `mongodb+srv://connection_data/${dbName}`;
console.log(`uri for stackoverflow:`, uri);
return { uri };
}
}
I've got a web server which returns this Organisation object by HTTP which is stored in 3-rd DB with a structure like:
{
param: string;
dbName: string;
}
So, when I get request, I have the param
by which to search dbName
in Organisations' DB on my web server.
I expect DB connection to use this MyMongooseConfigService
per request and every connection will go to appropriate DB. But that's not the case. I've got for example UserService
which gets users from correct Organisation. It looks something like:
@Injectable()
export class UserService {
constructor(
@InjectModel(User.name)
private userModel: Model<User>
) {}
async getUsers() {
console.log(`dbName for stackoverflow:`, this.userModel.db.name)
const users = await this.userModel.find();
}
}
The resulting users don't belong to correct organisation. So, what's wrong?
During initialisation mongoose make a connection attempt without actual request, and finds first available dbName
. I've even asked about this "init" connection in official NestJS Discord channel, there I've got the answer: the assumption is, you know what databases are supposed to be in use at the time the app starts
.
Web server that returns dbName
by param
makes search in DB like organisationModel.findOne({})
if no param
passed (I guess, it's serialisation when I make a request to web server) and it returns first Organisation in the list. So if I have in Organisations DB objects like:
{ param: '1234', dbName: 'org-1' }
and { param: '5678', dbName: 'org-2' }
the first found Organisation's dbName
will always be org-1
. If I remove all Organisations and add them in another order, the first found will always be org-2
And I've made console.log's for stackoverflow
on purpose in UserService
and in MyMongooseConfigService
. When I make a request with param 5678
I've got in logs:
uri for stackoverflow: mongodb+srv://connection_data/org-2
dbName for stackoverflow: org-1
This is the actual problem: connection uri in MyMongooseConfigService
is correct every time, but the model always returns the db.name
of the first connected DB. TS says that model.db.name
is "The name of the database this connection points to
".
Maybe I've done something wrong, forgot something? Can anyone help/guide?
I've tried to add @Injectable({ scope: Scope.REQUEST })
to UserService
. Seems like nothing has changed, because it all should bubble up to controller and to the request.