MongoDB là một lựa chọn tuyệt vời khi bạn cần một cơ sở dữ liệu NoSQL linh hoạt, dễ mở rộng. Khi kết hợp với NestJS – một framework mạnh mẽ dựa trên Node.js và TypeScript – bạn sẽ có một bộ công cụ cực kỳ hiệu quả để phát triển các ứng dụng hiện đại.
Trong bài viết này, chúng ta sẽ cùng khám phá cách tích hợp Mongoose – thư viện ORM/ODM phổ biến nhất cho MongoDB – vào NestJS. Bạn sẽ được hướng dẫn từng bước từ cấu hình cơ bản đến triển khai các tính năng CRUD phức tạp.
Mục lục
1. Giới thiệu MongoDB và So sánh với SQL
MongoDB là gì?
MongoDB là một hệ quản trị cơ sở dữ liệu NoSQL mã nguồn mở, được thiết kế để lưu trữ dữ liệu dưới dạng document (tài liệu), sử dụng cấu trúc JSON/BSON thay vì các bảng quan hệ như trong MySQL hay PostgreSQL.
Dữ liệu trong MongoDB trông giống như thế này:
{ "title": "Giới thiệu MongoDB", "content": "MongoDB là một cơ sở dữ liệu NoSQL mạnh mẽ...", "tags": ["NoSQL", "MongoDB", "Database"], "author": { "name": "Nguyễn Văn A", "email": "a@example.com" }
}
Ưu điểm của MongoDB
- Linh hoạt về cấu trúc dữ liệu: Không cần schema cố định, dễ thêm/xoá trường.
- Dễ scale theo chiều ngang: Hỗ trợ sharding, thích hợp cho hệ thống phân tán.
- Tốc độ cao với dữ liệu phi quan hệ: Rất hiệu quả khi làm việc với dữ liệu không cần liên kết chặt chẽ.
So sánh MongoDB với SQL
Tiêu chí | MongoDB (NoSQL) | SQL (MySQL, PostgreSQL,...) |
---|---|---|
Mô hình dữ liệu | Document (BSON/JSON) | Bảng (Table) với hàng và cột |
Schema | Không bắt buộc, linh hoạt | Phải định nghĩa rõ ràng trước |
Liên kết dữ liệu | Thông qua embedded documents hoặc ObjectId |
Dùng foreign key để liên kết bảng |
Truy vấn phức tạp | Hạn chế hơn, dùng cú pháp JSON | Hỗ trợ JOIN, GROUP BY, HAVING mạnh mẽ |
Tính toàn vẹn dữ liệu | Tùy thuộc vào ứng dụng quản lý | Rất chặt chẽ nhờ constraints (PK, FK, v.v.) |
Tốc độ truy xuất | Nhanh với dữ liệu phi quan hệ, cache tốt | Tốt với dữ liệu có quan hệ chặt chẽ |
Scale | Rất mạnh về horizontal scaling (sharding) | Thường mạnh về vertical scaling |
2. Giới thiệu về Mongoose và NestJS
- NestJS là framework cho Node.js sử dụng TypeScript, cấu trúc theo kiến trúc module và DI (Dependency Injection) tương tự Angular.
- Mongoose giúp bạn làm việc với MongoDB dễ dàng hơn bằng cách định nghĩa Schema, sử dụng Model, và thực hiện các thao tác với dữ liệu một cách trực quan, có kiểm soát.
3. Cài đặt NestJS và Mongoose
npm i -g @nestjs/cli
nest new nest-mongo-demo
cd nest-mongo-demo
npm install @nestjs/mongoose mongoose
Trong app.module.ts
:
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose'; @Module({ imports: [ MongooseModule.forRoot('mongodb://localhost/nest-blog-demo', { useNewUrlParser: true, }), ],
})
export class AppModule {}
4. Tạo Schema và Model với Mongoose
Giả sử xây dựng API blog với model Post
.
nest generate module posts
nest generate service posts
nest generate controller posts
Schema:
// posts/schemas/post.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose'; export type PostDocument = Post & Document; @Schema({ timestamps: true })
export class Post { @Prop({ required: true }) title: string; @Prop() content: string; @Prop() author: string;
} export const PostSchema = SchemaFactory.createForClass(Post);
Module:
// posts/posts.module.ts
import { MongooseModule } from '@nestjs/mongoose';
import { Module } from '@nestjs/common';
import { PostsService } from './posts.service';
import { PostsController } from './posts.controller';
import { Post, PostSchema } from './schemas/post.schema'; @Module({ imports: [MongooseModule.forFeature([{ name: Post.name, schema: PostSchema }])], providers: [PostsService], controllers: [PostsController],
})
export class PostsModule {}
5. Tạo Service và Controller cho API
Service
@Injectable()
export class PostsService { constructor(@InjectModel(Post.name) private postModel: Model<PostDocument>) {} async findAll(): Promise<Post[]> { return this.postModel.find().exec(); } async create(data: Partial<Post>): Promise<Post> { const createdPost = new this.postModel(data); return createdPost.save(); } async findOne(id: string): Promise<Post> { return this.postModel.findById(id).exec(); } async update(id: string, data: Partial<Post>): Promise<Post> { return this.postModel.findByIdAndUpdate(id, data, { new: true }).exec(); } async remove(id: string): Promise<void> { await this.postModel.findByIdAndDelete(id).exec(); }
}
Controller
@Controller('posts')
export class PostsController { constructor(private readonly postsService: PostsService) {} @Get() findAll() { return this.postsService.findAll(); } @Post() create(@Body() data: Partial<Post>) { return this.postsService.create(data); } @Get(':id') findOne(@Param('id') id: string) { return this.postsService.findOne(id); } @Patch(':id') update(@Param('id') id: string, @Body() data: Partial<Post>) { return this.postsService.update(id, data); } @Delete(':id') remove(@Param('id') id: string) { return this.postsService.remove(id); }
}
6. Sử dụng DTO và Validation
npm install class-validator class-transformer
DTO:
export class CreatePostDto { @IsNotEmpty() @IsString() title: string; @IsString() content: string; @IsString() author: string;
}
Bật validation:
app.useGlobalPipes(new ValidationPipe());
7. Quan hệ giữa các collection (References)
Trong MongoDB, có thể tạo mối liên hệ giữa các collection qua ObjectId
và populate
.
@Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'User' })
author: User;
return this.postModel.find().populate('author').exec();
8. Middleware và Hooks trong Mongoose
PostSchema.pre('save', function (next) { console.log('Saving post:', this); next();
});
9. Tips và Best Practices
- Luôn dùng DTO và
ValidationPipe
để lọc input. - Dùng
.lean()
nếu không cần full document. - Sử dụng indexes để tối ưu tìm kiếm.
- Xem xét transaction nếu dùng nhiều model liên quan.
10. Kết luận
NestJS và Mongoose là một sự kết hợp lý tưởng để xây dựng các API hiện đại, dễ mở rộng và maintain. MongoDB với tính linh hoạt cao giúp bạn thoải mái phát triển mà không cần quá lo về schema cố định ban đầu.
Nếu bạn đang phát triển startup, MVP hoặc app có cấu trúc dữ liệu động – đây là lựa chọn rất đáng thử!