NestJS - 如何在主应用程序模块文件中使用 .env 变量进行数据库连接

Moh*_*waj 23 javascript environment-variables node.js nestjs dotenv

我正在开发我的第一个 NestJS 应用程序,它在app.module.ts.

但是根据我们的要求,我不得不从环境文件中选择数据库配置值。为此,我遵循了 nestjs 文档网站上的配置文档 - https://docs.nestjs.com/techniques/configuration

但问题是我需要在同一个文件中使用 .env 变量进行数据库连接,这是失败的。

这是我运行良好的原始代码:

@Module({
  imports: [
    MongooseModule.forRoot(`mongodb+srv://myusername:mypassword@myhost.net?retryWrites=true&w=majority&db=dbname`, { useNewUrlParser: true, dbName: 'dbname' }),
    ProductModule,
    CategoryModule,
  ],
  controllers: [
    AppController,
    HealthCheckController,
  ],
  providers: [AppService, CustomLogger],
})
Run Code Online (Sandbox Code Playgroud)

现在,我想从.ENV文件,这是喜欢挑选那些DB值local.envdev.env取决于环境等。现在,我的这段代码不起作用:

@Module({
  imports: [
    ConfigModule.forRoot({ envFilePath: `${process.env.NODE_ENV}.env` }),
    MongooseModule.forRoot(`mongodb+srv://${ConfigModule.get('DB_USER')}:${ConfigModule.get('DB_PASS')}@myhost.net?retryWrites=true&w=majority&db=dbname`, { useNewUrlParser: true, dbName: 'dbname' }),
    ProductModule,
    CategoryModule,
  ],
  controllers: [
    AppController,
    HealthCheckController,
  ],
  providers: [AppService, CustomLogger],
})
Run Code Online (Sandbox Code Playgroud)

kos*_*kMD 32

MongooseModule.forRootAsync({
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => ({
    uri: configService.get<string>('MONGODB_URI'),
  }),
  inject: [ConfigService],
});
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的做法。假设您想通过配置模块运行所有内容,该模块可以在传入变量之前对变量进行验证。 (2认同)

swe*_*218 21

从这里的 Nestjs 文档 - https://docs.nestjs.com/techniques/configuration

这些步骤适用于 MySQL 和 TypeORM。

  1. 安装 Nestjs 配置模块 - npm i --save @nestjs/config. 它依赖于 dotenv

  2. 在您的根文件夹中创建一个 .env 文件并添加您的键/值对,例如 DATABASE_USER=myusername

  3. 打开 app.module.ts 并导入配置模块

    从'@nestjs/config' 导入 { ConfigModule };

  4. 将以下行添加到 app.module.ts 的导入部分。我将其添加为第一次导入。它将自动加载 .env 文件的内容。

    ConfigModule.forRoot(),

  5. 然后,您可以按照数据库配置部分中通常的 process.env.<variable_name> 开始使用 env 变量,例如

    process.env.DATABASE_USER

有关 ConfigModule 的更多配置,请参阅上面的链接。您可以使用自定义文件/路径并将模块设置为全局可见。

  • 这是 Nest.js 文档推荐的内容,以及付费 Nest.js 课程。然而,截至 2022 年中期,这种方法已经行不通了。我完全按照文档和课程中的步骤进行操作,并且收到“客户端密码必须是字符串”。我正在获取 ConfigModule 依赖项,然后抛出该错误。 (2认同)

top*_*oon 20

1. 继续使用 ConfigModule

您需要NODE_ENV在 npm 脚本中进行设置,以便它可以用于基于 env 加载一个 env 文件。

"scripts": {
  "start:local": "NODE_ENV=local npm run start"
  "start:dev": "NODE_ENV=dev npm run start"
}
Run Code Online (Sandbox Code Playgroud)

现在你可以只使用ConfigModule

@Module({
  imports: [
    ConfigModule.forRoot({ envFilePath: `${process.env.NODE_ENV}.env` }), 
MongooseModule.forRoot(`mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASS}@myhost.net?retryWrites=true&w=majority&db=dbname`, { useNewUrlParser: true, dbName: 'dbname' })
    ...
})
Run Code Online (Sandbox Code Playgroud)

2. 使用 dotenv

@Module({
  imports: [
    ConfigModule.forRoot({ envFilePath: `${process.env.NODE_ENV}.env` }), 
MongooseModule.forRoot(`mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASS}@myhost.net?retryWrites=true&w=majority&db=dbname`, { useNewUrlParser: true, dbName: 'dbname' })
    ...
})
Run Code Online (Sandbox Code Playgroud)

向您添加一些脚本以package.json设置您所在的环境。

npm install dotenv
Run Code Online (Sandbox Code Playgroud)

dotenvmain.ts文件中导入。确保在文件顶部执行此操作。

"scripts": {
  ...
  "start:local": "NODE_ENV=local npm run start"
  "start:dev": "NODE_ENV=dev npm run start"
}
Run Code Online (Sandbox Code Playgroud)

3. 使用 env-cmd

您可以使用env-cmdnpm 包。

require('dotenv').config({ path: `../${process.env.NODE_ENV}.env` });
Run Code Online (Sandbox Code Playgroud)

并在 中为不同的环境添加一些命令package.json,例如:

npm install env-cmd
Run Code Online (Sandbox Code Playgroud)

现在您可以使用 env 变量,例如:

"scripts": {
  ...
  "start:local": "env-cmd -f local.env npm run start"
  "start:dev": "env-cmd -f dev.env npm run start"
}
...
Run Code Online (Sandbox Code Playgroud)

process.env.MONGO_CONNECTION_STRING

  • Nest 配置服务的底层已经有了“dotenv” (4认同)
  • 谢谢。我尝试了你的第一个建议,它对我来说效果很好(唯一的问题是 require('dotenv') 行必须在导入 AppModule 之前出现)。这个解决方案既简单又快捷:) (2认同)

小智 11

通过使用 nestjs/config 包:

npm 安装 @nestjs/config

安装包后,在app模块(app.module.ts文件)中:

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [ConfigModule.forRoot()],
})

export class AppModule {}
Run Code Online (Sandbox Code Playgroud)

之后 .env 文件可以在整个应用程序中访问。假设您的 .env 文件如下所示。

DB_USER=mohit
Run Code Online (Sandbox Code Playgroud)

访问 DB_USER 变量使用 process.env.DB_USER

  • 这完成了在运行时获取环境变量的工作,但 OP 还想在导入模块时获取环境变量。正如@Daniel 指出的那样,通过您的解决方案,OP 需要异步加载猫鼬模块。 (3认同)

Dan*_*iel 8

您需要使用MongooseModule.forRootAsync(() => {...})代替MongooseModule.forRoot(...)

这使得 MongooseModule 等待其 IOC 依赖项。

请参阅:https : //docs.nestjs.com/techniques/mongodb#async-configuration

  • 我按照您的建议更新了我的代码。但现在我收到错误 - “Nest 无法导出不属于当前处理模块的模块”。这是我更新的内容 - `MongooseModule.forRootAsync({ import: [ConfigModule], useFactory: async (configService: ConfigService) =&gt; ({ uri: 'mongodb+srv://db_username:db_pass@myhost.net?retryWrites=true&amp;w =majority', options: { useNewUrlParser: true, dbName: 'dbname' }, }), 注入: [ConfigModule], }),` (2认同)
  • 修复从“ConfigModule”到“ConfigService”的注入(遵循 NestJS 文档) (2认同)