You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置NestJS运行mongosh脚本并实现SaaS用户专属MongoDB动态创建与连接

问题解答:NestJS + MongoDB 实现SaaS用户专属数据库方案

一、NestJS 配置动态创建MongoDB数据库脚本

首先提前安装依赖:@nestjs/mongoose mongoose,分两步完成基础配置:

1. 主数据库连接配置

先配置全局的主数据库连接,用于存储所有用户的专属数据库元信息,在app.module.ts中引入:

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

@Module({
  imports: [
    MongooseModule.forRoot('mongodb://localhost:27017/saas-main', {
      connectionName: 'main',
    }),
    // 其他业务模块引入
  ],
})
export class AppModule {}

2. 注册逻辑嵌入建库脚本

在用户注册的Service逻辑中,直接调用mongoose的连接方法创建新库,同时将库信息写入主库:

import { Injectable } from '@nestjs/common';
import { InjectConnection, InjectModel } from '@nestjs/mongoose';
import { Connection, Model, createConnection } from 'mongoose';
import { UserDb, UserDbDocument } from './schemas/user-db.schema'; // 主库存储用户库信息的Schema

@Injectable()
export class AuthService {
  constructor(
    @InjectConnection('main') private mainConnection: Connection,
    @InjectModel(UserDb.name, 'main') private userDbModel: Model<UserDbDocument>,
  ) {}

  async register(userInfo: any) {
    // 第一步:创建主库的用户基础账号信息
    const newUserId = 'xxx'; // 替换为实际生成的用户ID
    // 第二步:生成用户专属库名,可自定义规则,比如`saas_user_${userId}`
    const userDbName = `saas_user_${newUserId}`;
    // 第三步:动态创建数据库连接,写入任意集合一条数据即可触发MongoDB自动建库
    const userConnection = await createConnection(`mongodb://localhost:27017/${userDbName}`).asPromise();
    // 可按需初始化用户库的默认集合,比如配置表、初始数据
    await userConnection.collection('system_config').insertOne({ initStatus: true, createTime: new Date() });
    await userConnection.close();
    // 第四步:将用户库元信息存入主库,生产环境可配置带权限的数据库访问账号密码
    await this.userDbModel.create({
      userId: newUserId,
      dbName: userDbName,
      dbUri: `mongodb://localhost:27017/${userDbName}`,
    });
    // 后续返回注册结果即可
  }
}

二、用户登录时动态连接专属数据库

建议新增连接池缓存逻辑,避免每次请求都新建连接消耗性能:

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Connection, Model, createConnection } from 'mongoose';
import { UserDb, UserDbDocument } from './schemas/user-db.schema';

@Injectable()
export class DbConnectionService {
  // 缓存已创建的连接,key为用户ID
  private connectionPool: Map<string, Connection> = new Map();

  constructor(
    @InjectModel(UserDb.name, 'main') private userDbModel: Model<UserDbDocument>,
  ) {}

  async getUserConnection(userId: string): Promise<Connection> {
    // 优先读取缓存
    if (this.connectionPool.has(userId)) {
      return this.connectionPool.get(userId);
    }
    // 从主库查询用户专属库信息
    const userDbInfo = await this.userDbModel.findOne({ userId });
    if (!userDbInfo) {
      throw new Error('用户专属数据库不存在');
    }
    // 新建数据库连接
    const connection = await createConnection(userDbInfo.dbUri).asPromise();
    // 存入缓存,可额外添加过期回收逻辑,长时间不用的连接自动关闭并清除缓存
    this.connectionPool.set(userId, connection);
    return connection;
  }
}

用户登录后,后续业务请求可从JWT或Session中提取用户ID,调用上述getUserConnection方法拿到对应库的连接,即可操作对应集合完成业务逻辑。

三、场景优化方案参考

你当前的按用户分库方案适合数据隔离要求极高的场景,但如果用户量达到十万级以上,会存在MongoDB实例性能下降、连接数易打满、备份运维成本高的问题,可根据业务实际需求选择更适配的方案:

  • 低隔离需求:所有用户数据存在同一个库的同一个集合,每个文档新增userId字段做区分,查询时强制添加userId过滤条件,开发运维成本最低,性能最优。
  • 中等隔离需求:同一个数据库下,每个用户对应独立集合,集合名按${collectionName}_${userId}规则命名,比全表隔离的隔离性更高,单集合数据量更小,查询性能更好。
  • 高隔离需求:保留现有分库方案,优化点为将用户库按分片规则分布到不同MongoDB集群节点,避免单节点压力过大,同时补充连接池自动回收逻辑,控制单实例连接数上限。

内容的提问来源于stack exchange,提问作者Muhammad Khalil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 14:18:04