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
中引入 UserController
及 UserService
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 {}
controllers
將Controller
註冊到這個 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 中的資料, 現在可以使用 postman
或 curl
來測試看看是否成功.