Skip to main content

Basic Use (GET)

前面的設定 中我們已經設定好了 MongoDB 的連線, 現在我們可以開始使用 MongoDB, 假設我們的 DB 已經有存放了 users 的資料, 並且其中有一個欄位是 email, 我們可以透過以下方式來取得資料:

1. 建立一個 users 的 schema

users.schema.ts
import { ModelDefinition, Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
import { signupStrategy } from '@/common/constants';

export type UserDocument = User & Document;

@Schema()
export class User {
@Prop({
required: true,
lowercase: true,
maxLength: 30,
unique: true
})
email: string;

@Prop({
required: true,
minLength: 8,
maxLength: 24
})
password: string;

@Prop({
required: true,
enum: [signupStrategy.GENERAL, signupStrategy.GOOGLE, signupStrategy.LINE]
})
signUpStrategy: string;

@Prop({
required: true,
default: Date.now
})
createdAt: Date;
}

export const UserSchema = SchemaFactory.createForClass(User);
export const USER_MODEL_TOKEN = User.name;

export const UserDefinition: ModelDefinition = {
name: USER_MODEL_TOKEN,
schema: UserSchema
};
  • export type UserDocument = User & Document; 是將 User 和 Document 兩個型別組合在一起, 建立一個新的型別 UserDocument, 這個新的型別既有 User 的所有屬性和方法, 也有 Document 的所有屬性和方法
  • SchemaFactory.createForClass@nestjs/mongoose 提供的方法, 用來建立一個 schema, 其中針對每一個設定的爛位, 可以搭配 @Prop() 來設定, 例如 required, unique, default, enum ...etc.
  • USER_MODEL_TOKEN 是用來在其他地方引用這個 schema 的 unique 名稱
  • UserDefinition 是用來在 database.module.ts 中引入這個 schema 的設定

2. 建立一個 users 的 service

users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { FilterQuery, Model } from 'mongoose';
import { USER_MODEL_TOKEN, UserDocument } from '@/common/models/user.schema';

@Injectable()
export class UserService {
constructor(
@InjectModel(USER_MODEL_TOKEN)
private readonly userModel: Model<UserDocument>
) {}

async findUserByEmail({ email }: { email: string }) {
const filter: FilterQuery<UserDocument> = { email };
return this.userModel.findOne(filter).lean();
}
}
  • @InjectModel(USER_MODEL_TOKEN) 是一個裝飾器 (Decorator), 它告訴 NestJS 我們想要注入一個 Mongoose 模型到這個服務中. USER_MODEL_TOKEN 是我們在定義模型時給定的名稱, 所以 NestJS 會使用這個名稱來找到對應的模型.
  • private readonly userModel: Model<UserDocument> 是一個私有屬性, 用來存放注入的模型, 這樣我們就可以在這個服務中使用這個模型來操作資料庫, 也就是說可以透過 this.userModel 來操作 users 這個 collection

我們在 UserService 底下新增一個方法 findUserByEmail, 這個方法接收一個物件 { email: string } 作為參數, 並且透過 this.userModel.findOne(filter).lean() 從 db 找到符合條件的資料並回傳.

3. 建立一個 users 的 controller

users.controller.ts
import { Controller, Get, Query } from '@nestjs/common';
import { UserService } from '@/features/user/user.service';

@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}

@Get()
async getUserByEmail(@Query('email') email: string) {
return this.userService.findUserByEmail({ email });
}
}
  • constructor(private readonly userService: UserService) {} 同上面 UserService 的用途一樣, 這裡是注入一個 UserService 到這個 controller 中, 這樣我們就可以在這個 controller 中使用 UserService 提供的方法來操作資料
  • @Get() 是一個裝飾器 (Decorator), 它告訴 NestJS 這個方法是一個 GET 方法, 這樣 NestJS 就會將這個方法註冊到路由中, 並且可以透過 ${YOUR_DOMAIN}/api/user?email=xxx 來呼叫這個方法
  • @Query('email') email: string 是一個裝飾器 (Decorator), 它告訴 NestJS 我們想要從 query string 中取得 email 這個參數, 並且將這個參數存放到 email 這個變數中, 除了 @Query() 之外, NestJS 還有提供 @Param(), @Body() 等其他裝飾器, 用來取得相關路由參數, body 參數等

4. 在 user.module.ts 中引入 UserControllerUserService

user.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UserDefinition } from '@/common/models/user.schema';

import { UserService } from './user.service';
import { UserController } from './user.controller';

@Module({
controllers: [UserController],
imports: [MongooseModule.forFeature([UserDefinition])],
providers: [UserService],
exports: [MongooseModule.forFeature([UserDefinition]), UserService]
})
export class UserModule {}
  • controllersController 註冊到這個 module 中, 這樣 NestJS 就可以知道這個 module 中有哪些 controller, 而 Controller 是負責處理進來的 HTTP 請求並發送適當的回應, 它們會定義路由以及處理請求的方法.
  • providers 是模組中定義的元件, 它們可以是各種服務、業務邏輯, 這些 Provider 是模組內的私有元件, 只有在同個模組內才能使用, 而在模組內, 你可以將這些 Provider 注入到 Controller, Service 或其他 Provider 中, 以實現所需要的功能, 以上面來說就是將 userService 註冊到這個 module 中, 這樣我們就可以在這個 module 中使用 userService 提供的方法來操作資料
  • MongooseModule.forFeature 是用來引入一個或多個 schema 到這個 module 中, 這樣我們就可以在這個 module 中使用這些 schema 來操作資料庫
  • imports 是用來引入其他 module 到這個 module 中, 這樣我們就可以在這個 module 中使用其他 module 提供的服務, 且在這個 Module 底下的 Provider 也都可以使用這些服務, 這是 NestJS 中實現模組重複使用和組合功能的重要方式
  • exports 相反於 providers, 是用來將這個 Module 所擁有的服務 export 出去, 這樣其他 module 就可以使用這些服務

5. 最後在 app.module.ts 也就是我們的 root 中引入 UserModule

app.module.ts
import { UserModule } from '@/features/user/user.module';
@Module({
imports: [...loadConfigImports(), UserModule] // <--- import UserModule
// ...
})
export class AppModule {}

這樣就完成了一個簡單的 GET 方法, 透過 ${YOUR_DOMAIN}/api/user?email=xxx 來取得 MongoDB 中的資料, 現在可以使用 postmancurl 來測試看看是否成功.

basic-use-1.png