hocvietcode.com
  • Trang chủ
  • Học lập trình
    • Lập trình C/C++
    • Cấu trúc dữ liệu và giải thuật
    • Lập trình HTML
    • Lập trình Javascript
      • Javascript cơ bản
      • ReactJS framework
      • AngularJS framework
      • Typescript cơ bản
      • Angular
      • NodeJS
    • Lập trình Mobile
      • Lập Trình Dart Cơ Bản
        • Dart Flutter Framework
    • Cơ sở dữ liệu
      • MySQL – MariaDB
      • Micrsoft SQL Server
      • Extensible Markup Language (XML)
      • JSON
      • MongoDB
    • Lập trình PHP
      • Lập trình PHP cơ bản
      • Laravel Framework
    • Lập trình Java
      • Java Cơ bản
      • Spring Boot
    • Lập trình C#
      • Lập Trình C# Cơ Bản
      • ASP.NET Core MVC
    • Lập trình Python
    • Git và Github
    • Machine Learning
  • WORDPRESS
    • WordPress cơ bản
    • WordPress nâng cao
    • Chia sẻ WordPress
  • Kiến thức hệ thống
    • Microsoft Azure
    • Docker
    • Linux
    • Mạng và truyền thông
  • Chia sẻ IT
    • Tin học văn phòng
      • Microsoft Word
      • Microsoft Excel
    • Marketing
      • Google Adwords
      • Facebook Ads
      • Kiến thức khác
    • Chia sẻ phần mềm
    • Review công nghệ
    • Công cụ – tiện ích
      • Kiểm tra bàn phím online
      • Kiểm tra webcam online
Đăng nhập
  • Đăng nhập / Đăng ký

Please enter key search to display results.

Home
  • NodeJS
Kết nối MongoDB và xây dựng CRUD API

Kết nối MongoDB và xây dựng CRUD API

  • 24-07-2026
  • Toanngo92
  • 0 Comments

Trong bài trước, chúng ta đã xây dựng API với Express. Bài này bổ sung mảnh ghép quan trọng của ứng dụng thực tế: lưu dữ liệu lâu dài trong MongoDB. Bạn sẽ kết nối Node.js với MongoDB, thao tác CRUD và hoàn thiện API quản lý sách có thể kiểm thử bằng curl hoặc Postman.

Node.js Bài 9 - tích hợp Node.js với MongoDB
Session 9: Integration of Node.js with MongoDB (trang 206).

Mục lục

  • 1. Mục tiêu bài học
  • 2. Node.js làm việc với cơ sở dữ liệu như thế nào?
  • 3. Chuẩn bị MongoDB và dự án
  • 4. Tạo kết nối dùng chung
  • 5. CRUD trong MongoDB
  • 6. Create và Read
  • 7. ObjectId, Update và Delete
  • 8. Xây dựng REST API Express
  • 9. API tạo, sửa và xóa
  • 10. Khởi động và xử lý lỗi tập trung
  • 11. Kiểm thử API bằng curl
  • 12. Lỗi thường gặp
  • 13. Bài tập thực hành
  • Tổng kết
  • Phần 1: Kết nối và khởi tạo cơ sở dữ liệu (4 điểm)
  • Phần 2: Xây dựng chức năng đăng ký tài khoản (4 điểm)
  • Phần 3: Xây dựng chức năng đăng nhập (4 điểm)
  • Phần 4: Xây dựng chức năng đặt lại mã PIN (4 điểm)
  • Phần 5: Xây dựng chức năng thay đổi mã PIN (4 điểm)

1. Mục tiêu bài học

  • Hiểu vai trò của driver khi Node.js giao tiếp với cơ sở dữ liệu.
  • Kết nối bằng MongoDB Node.js Driver chính thức.
  • Dùng insertOne, find, findOne, updateOne và deleteOne.
  • Xử lý ObjectId, mã trạng thái HTTP và lỗi đầu vào.
  • Xây dựng REST API CRUD bằng Express và MongoDB.

2. Node.js làm việc với cơ sở dữ liệu như thế nào?

Một driver đứng giữa ứng dụng và máy chủ cơ sở dữ liệu, chuyển lời gọi JavaScript thành giao thức MongoDB, quản lý kết nối và chuyển kết quả trở lại cho Node.js. Node.js hỗ trợ cả cơ sở dữ liệu quan hệ như MySQL, PostgreSQL, SQL Server và phi quan hệ như MongoDB, Redis hoặc Cassandra. MongoDB phù hợp với JavaScript vì dữ liệu document rất gần với object.

Cơ sở dữ liệu hỗ trợ Node.js

Một số hệ quản trị cơ sở dữ liệu có thể dùng với Node.js.

3. Chuẩn bị MongoDB và dự án

Bạn có thể dùng MongoDB Community trên máy hoặc MongoDB Atlas. Với môi trường cục bộ, URI thường là mongodb://127.0.0.1:27017. Không đưa mật khẩu hoặc connection string thật lên Git.

mkdir node-mongodb-api
cd node-mongodb-api
npm init -y
npm install express mongodb dotenv
# .env
MONGODB_URI=mongodb://127.0.0.1:27017
PORT=3000
Quy trình kết nối MongoDB với Node.js

Cài MongoDB, chuẩn bị môi trường, cài driver và kết nối.

4. Tạo kết nối dùng chung

Mỗi tiến trình nên tạo một MongoClient rồi tái sử dụng. Driver đã có connection pool; tạo client mới trong từng request vừa chậm vừa làm tăng số kết nối.

// db.js
const { MongoClient } = require('mongodb');
const uri = process.env.MONGODB_URI ?? 'mongodb://127.0.0.1:27017';
const client = new MongoClient(uri);
let database;

async function connectDatabase() {
  await client.connect();
  database = client.db('library');
  await database.command({ ping: 1 });
  console.log('Đã kết nối MongoDB');
}
function getDatabase() {
  if (!database) throw new Error('MongoDB chưa được kết nối');
  return database;
}
module.exports = { client, connectDatabase, getDatabase };

5. CRUD trong MongoDB

Dữ liệu MongoDB được tổ chức thành database, collection và document. Ví dụ dùng database library, collection books. Mỗi document mặc định có trường _id kiểu ObjectId.

Bốn thao tác CRUD trong MongoDB

Create, Read, Update và Delete trên collection.

6. Create và Read

const books = db.collection('books');

const result = await books.insertOne({
  name: 'Node.js thực chiến',
  author: 'Học Viết Code',
  price: 180000,
  createdAt: new Date()
});
console.log(result.insertedId);

const allBooks = await books
  .find({})
  .sort({ createdAt: -1 })
  .limit(20)
  .toArray();

find() trả về cursor, vì vậy cần gọi toArray() để nhận mảng kết quả. Khi chỉ cần một document, dùng findOne().

7. ObjectId, Update và Delete

req.params.id là chuỗi, còn _id mặc định là ObjectId. Luôn kiểm tra định dạng trước khi chuyển đổi để API có thể trả lỗi 400 rõ ràng.

const { ObjectId } = require('mongodb');

if (!ObjectId.isValid(id)) {
  throw new Error('ID không hợp lệ');
}
const _id = new ObjectId(id);

await books.updateOne(
  { _id },
  { $set: { price: 210000, updatedAt: new Date() } }
);

await books.deleteOne({ _id });

Với cập nhật, kiểm tra matchedCount; với xóa, kiểm tra deletedCount. Nếu bằng 0, API nên trả 404.

8. Xây dựng REST API Express

require('dotenv').config();
const express = require('express');
const { ObjectId } = require('mongodb');
const { connectDatabase, getDatabase } = require('./db');

const app = express();
app.use(express.json());
const books = () => getDatabase().collection('books');

app.get('/books', async (req, res, next) => {
  try {
    res.json(await books().find({}).limit(100).toArray());
  } catch (error) { next(error); }
});

app.get('/books/:id', async (req, res, next) => {
  try {
    if (!ObjectId.isValid(req.params.id)) {
      return res.status(400).json({ message: 'ID không hợp lệ' });
    }
    const book = await books().findOne({
      _id: new ObjectId(req.params.id)
    });
    if (!book) return res.status(404).json({ message: 'Không tìm thấy sách' });
    res.json(book);
  } catch (error) { next(error); }
});

9. API tạo, sửa và xóa

app.post('/books', async (req, res, next) => {
  try {
    const { name, author, price } = req.body;
    if (!name || !author || !Number.isFinite(price)) {
      return res.status(400).json({ message: 'Dữ liệu không hợp lệ' });
    }
    const book = { name, author, price, createdAt: new Date() };
    const result = await books().insertOne(book);
    res.status(201).json({ ...book, _id: result.insertedId });
  } catch (error) { next(error); }
});

app.put('/books/:id', async (req, res, next) => {
  try {
    if (!ObjectId.isValid(req.params.id)) return res.status(400).json({ message: 'ID không hợp lệ' });
    const result = await books().updateOne(
      { _id: new ObjectId(req.params.id) },
      { $set: { ...req.body, updatedAt: new Date() } }
    );
    if (!result.matchedCount) return res.status(404).json({ message: 'Không tìm thấy sách' });
    res.json({ message: 'Cập nhật thành công' });
  } catch (error) { next(error); }
});

app.delete('/books/:id', async (req, res, next) => {
  try {
    if (!ObjectId.isValid(req.params.id)) return res.status(400).json({ message: 'ID không hợp lệ' });
    const result = await books().deleteOne({ _id: new ObjectId(req.params.id) });
    if (!result.deletedCount) return res.status(404).json({ message: 'Không tìm thấy sách' });
    res.status(204).end();
  } catch (error) { next(error); }
});
Endpoint Express CRUD với MongoDB

Các phương thức và endpoint CRUD trong giáo trình.

10. Khởi động và xử lý lỗi tập trung

app.use((error, req, res, next) => {
  console.error(error);
  res.status(500).json({ message: 'Lỗi máy chủ' });
});

async function start() {
  await connectDatabase();
  app.listen(process.env.PORT ?? 3000, () => {
    console.log('API chạy tại http://localhost:3000');
  });
}
start().catch(console.error);

Ứng dụng chỉ lắng nghe sau khi kết nối cơ sở dữ liệu thành công. Khi tiến trình dừng, hãy gọi client.close() để giải phóng tài nguyên.

11. Kiểm thử API bằng curl

curl http://localhost:3000/books

curl -X POST http://localhost:3000/books \
  -H "Content-Type: application/json" \
  -d '{"name":"Node.js căn bản","author":"An","price":150000}'

curl -X DELETE http://localhost:3000/books/BOOK_ID
Kiểm thử CRUD MongoDB bằng curl

Kiểm thử thao tác đọc và tạo sách qua trình duyệt/curl.

12. Lỗi thường gặp

  • ECONNREFUSED: MongoDB chưa chạy hoặc URI sai.
  • Authentication failed: sai tài khoản, mật khẩu hoặc authentication database.
  • Không tìm thấy document: quên chuyển chuỗi ID thành ObjectId.
  • req.body là undefined: thiếu app.use(express.json()).
  • Quá nhiều kết nối: tạo MongoClient trong từng request.
  • API chậm: thiếu index, phân trang hoặc giới hạn bản ghi.

13. Bài tập thực hành

  1. Thêm trường category và endpoint lọc sách theo thể loại.
  2. Thêm phân trang bằng page, limit, skip() và limit().
  3. Tạo unique index cho ISBN và xử lý lỗi trùng dữ liệu.
  4. Viết middleware kiểm tra dữ liệu đầu vào.
  5. Tách router, controller và repository thành các module riêng.

Tổng kết

Bạn đã đi từ kết nối MongoDB đến REST API CRUD hoàn chỉnh. Hãy giữ connection string trong biến môi trường, tái sử dụng một MongoClient cho mỗi tiến trình và luôn kiểm tra dữ liệu đầu vào cùng ObjectId. Đây là nền tảng để xây dựng ứng dụng Node.js có xác thực, phân trang và triển khai thực tế.

Bài tập 1:

Chủ đề: Xây dựng hệ thống quản lý tài khoản Library Kiosk (Thư viện tự phục vụ)

Tổng điểm: 20 điểm Công nghệ sử dụng: Node.js, Express.js, MongoDB, bcrypt Hình thức: Thực hành lập trình

Phần 1: Kết nối và khởi tạo cơ sở dữ liệu (4 điểm)

Viết một file JavaScript (ví dụ: db.js) có thể được sử dụng trong các file khác thông qua require() hoặc import.

Yêu cầu:

  • (1 điểm) Kết nối đến MongoDB bằng thư viện mongoose và xuất kết nối hoặc model để các file khác có thể sử dụng.
  • (1 điểm) Sử dụng cơ sở dữ liệu có tên library_kiosk. Nếu cơ sở dữ liệu chưa tồn tại, chương trình phải tạo cơ sở dữ liệu khi khởi tạo dữ liệu.
  • (1 điểm) Định nghĩa Schema và Model cho collection kiosk_accounts với các trường sau:
Tên trườngKiểu dữ liệuRàng buộc
usernameStringRequired, Unique, Maxlength: 100
pin_hashStringRequired
student_idStringRequired, Maxlength: 12

– (1 điểm) Nếu xảy ra lỗi trong quá trình kết nối hoặc thực hiện thao tác với MongoDB, chương trình phải hiển thị thông báo lỗi và xử lý hoặc dừng thao tác phù hợp.

Lưu ý: Trường pin_hash lưu mã PIN đã được băm bằng bcrypt. Không lưu PIN dạng văn bản thuần. Cần tạo unique index cho username để bảo đảm tính duy nhất.

Phần 2: Xây dựng chức năng đăng ký tài khoản (4 điểm)

Viết chức năng đăng ký tài khoản bằng Express.js (ví dụ: register.js).

Yêu cầu:

  • (1 điểm) Xây dựng route GET /register hiển thị biểu mẫu đăng ký gồm 3 trường:
    • username: Tên đăng nhập
    • pin: Mã PIN
    • student_id: Mã sinh viên
    Biểu mẫu sử dụng phương thức POST gửi dữ liệu đến /register.
  • (1 điểm) Khi nhận dữ liệu đăng ký, sử dụng Mongoose để kiểm tra username đã tồn tại trong collection kiosk_accounts hay chưa. Nếu tồn tại, hiển thị thông báo “Tên đăng nhập đã tồn tại” và hiển thị lại biểu mẫu trống.
  • (2 điểm) Nếu tên đăng nhập chưa tồn tại:
    • Sử dụng bcrypt.hash() với salt rounds bằng 10 để băm mã PIN.
    • Thêm tài khoản mới vào collection kiosk_accounts.
    • Hiển thị thông báo “Đăng ký tài khoản thành công”, kèm theo username và student_id vừa đăng ký.

Phần 3: Xây dựng chức năng đăng nhập (4 điểm)

Viết chức năng đăng nhập bằng Express.js (ví dụ: login.js).

Yêu cầu:

  • (1 điểm) Xây dựng route GET /login hiển thị biểu mẫu đăng nhập gồm:
    • username: Tên đăng nhập
    • pin: Mã PIN
  • (1 điểm) Khi người dùng gửi biểu mẫu bằng phương thức POST đến /login:
    • Sử dụng Mongoose để tìm tài khoản theo username.
    • Sử dụng bcrypt.compare() để kiểm tra mã PIN nhập vào với pin_hash đã lưu trong MongoDB.
    • Nếu chính xác, hiển thị thông báo:
    “Chào mừng USERNAME đến với Library Kiosk”Trong đó USERNAME được thay bằng tên đăng nhập thực tế.
  • (2 điểm) Nếu tên đăng nhập không tồn tại hoặc PIN không chính xác:
    • Hiển thị thông báo “Tên đăng nhập hoặc mã PIN không chính xác”.
    • Hiển thị lại biểu mẫu đăng nhập để người dùng nhập lại.

Phần 4: Xây dựng chức năng đặt lại mã PIN (4 điểm)

Viết chức năng đặt lại mã PIN bằng Express.js (ví dụ: reset_pin.js).

Yêu cầu:

  • (1 điểm) Xây dựng route GET /reset-pin hiển thị biểu mẫu gồm:
    • username: Tên đăng nhập
    • student_id: Mã sinh viên
  • (2 điểm) Khi người dùng gửi biểu mẫu bằng phương thức POST đến /reset-pin:
    • Sử dụng Mongoose để tìm tài khoản có username và student_id tương ứng trong MongoDB.
    • Nếu thông tin chính xác:
      • Sử dụng module crypto của Node.js để tạo ngẫu nhiên một mã PIN mới gồm 8 ký tự chữ và số.
      • Băm mã PIN mới bằng bcrypt với salt rounds bằng 10.
      • Sử dụng phương thức cập nhật của Mongoose để thay đổi pin_hash trong collection kiosk_accounts.
      • Hiển thị thông báo “Đặt lại mã PIN thành công” và mã PIN vừa tạo cho người dùng.
  • (1 điểm) Nếu thông tin username hoặc student_id không chính xác:
    • Hiển thị thông báo “Không tìm thấy tài khoản phù hợp”.
    • Hiển thị lại biểu mẫu đặt lại PIN bên dưới thông báo.

Phần 5: Xây dựng chức năng thay đổi mã PIN (4 điểm)

Viết chức năng thay đổi mã PIN bằng Express.js (ví dụ: change_pin.js).

Yêu cầu:

  • (1 điểm) Xây dựng route GET /change-pin hiển thị biểu mẫu gồm:
    • username: Tên đăng nhập
    • current_pin: Mã PIN hiện tại
    • new_pin: Mã PIN mới
  • (2 điểm) Khi người dùng gửi biểu mẫu bằng phương thức POST đến /change-pin:
    • Sử dụng Mongoose để tìm tài khoản theo username.
    • Sử dụng bcrypt.compare() để xác minh current_pin với pin_hash trong MongoDB.
    • Nếu thông tin chính xác:
      • Băm new_pin bằng bcrypt với salt rounds bằng 10.
      • Cập nhật trường pin_hash của tài khoản trong MongoDB.
      • Hiển thị thông báo “Thay đổi mã PIN thành công”.
  • (1 điểm) Nếu tên đăng nhập không tồn tại hoặc mã PIN hiện tại không chính xác:
    • Không thực hiện cập nhật dữ liệu.
    • Hiển thị thông báo “Thay đổi mã PIN thất bại”.
    • Hiển thị lại biểu mẫu để người dùng nhập lại thông tin.

Bài viết liên quan:

Hoàn thiện ứng dụng quản lý phim, xác thực và triển khai Render
Xây dựng ứng dụng quản lý phim với Express, EJS và MongoDB
Xây dựng website với Express, EJS và MongoDB
Xây dựng RESTful API với Express và HTTP trong nodejs
Đồng bộ, bất đồng bộ, Promise, async/await và Event Loop
Express.js, Routing, GET/POST và Middleware
Query String, gửi Email, Upload File và Local Modules trong Node.js
Built-in Modules trong Node.js: HTTP Server, URL và EventEmitter
Modules và Packages trong Node.js: CommonJS, ES Modules, npm và File System
Node.js Essentials: kiến trúc, Event Loop, REPL, npm và Global Objects
Node.js là gì? Kiến trúc client-server và cách cài đặt Node.js
Tìm Hiểu Express.js và Lập Trình Đồng Bộ – Bất Đồng Bộ Trong Node.js

THÊM BÌNH LUẬN Cancel reply

Dịch vụ thiết kế Wesbite

NỘI DUNG MỚI CẬP NHẬT

CSS cơ bản – 20 bài từ HTML đến website responsive với Flexbox, Grid và mobile-first

CSS cơ bản – Bài 05: Đơn vị và kích thước: px, rem, %, min và max

CSS cơ bản – 20 bài từ HTML đến website responsive với Flexbox, Grid và mobile-first

CSS cơ bản – Bài 02: Selector và class: chọn đúng phần tử cần sửa

CSS cơ bản – 20 bài từ HTML đến website responsive với Flexbox, Grid và mobile-first

CSS cơ bản – Bài 01: Kết nối CSS với HTML và sửa quy tắc đầu tiên

CSS cơ bản – 20 bài từ HTML đến website responsive với Flexbox, Grid và mobile-first

CSS cơ bản – Bài 20: Hoàn thiện website và sửa lỗi bằng DevTools

CSS cơ bản – 20 bài từ HTML đến website responsive với Flexbox, Grid và mobile-first

CSS cơ bản – Bài 03: Vì sao CSS không có tác dụng? Cascade và specificity

Giới thiệu

hocvietcode.com là website chia sẻ và cập nhật tin tức công nghệ, chia sẻ kiến thức, kỹ năng. Chúng tôi rất cảm ơn và mong muốn nhận được nhiều phản hồi để có thể phục vụ quý bạn đọc tốt hơn !

Liên hệ quảng cáo: [email protected]

Kết nối với HỌC VIẾT CODE

© hocvietcode.com - Tech888 Co .Ltd since 2019

Đăng nhập

Trở thành một phần của cộng đồng của chúng tôi!
Registration complete. Please check your email.
Đăng nhập bằng google
Đăng kýBạn quên mật khẩu?

Create an account

Welcome! Register for an account
The user name or email address is not correct.
Registration confirmation will be emailed to you.
Log in Lost your password?

Reset password

Recover your password
Password reset email has been sent.
The email could not be sent. Possible reason: your host may have disabled the mail function.
A password will be e-mailed to you.
Log in Register
×