+1

MongoDB Document Model và CRUD Thực Chiến

Với developer, việc chọn database thường quyết định độ linh hoạt kiến trúc ứng dụng. Nếu bạn quen với database quan hệ như MySQL hay PostgreSQL, lần đầu tiếp xúc MongoDB sẽ có cảm giác thay đổi tư duy.

Bài này sẽ khám phá lý do MongoDB được thiết kế như vậy, và cách thực hiện các thao tác CRUD cơ bản, tập trung vào cách document model map với nhu cầu ứng dụng thực tế.

image.png


Tư duy bảng: Thế giới Relational Database

Trong database quan hệ, dữ liệu được sắp xếp gọn gàng theo hàng và cột, giống như bảng Excel. Schema phải định nghĩa trước:

  • Mọi hàng phải tuân theo định nghĩa bảng.
  • Cột có kiểu dữ liệu cố định, trừ khi chạy migration.

Ưu điểm:

  • Đảm bảo tính nhất quán mạnh.
  • Mô hình dữ liệu có cấu trúc rõ ràng.

Nhược điểm:

  • Thay đổi schema đau đầu khi scale.
  • Thêm cột mới cho bảng tỷ hàng có thể cần migration dài và rủi ro downtime.

Với sản phẩm thay đổi nhanh, độ cứng nhắc này trở thành bottleneck rõ rệt.


NoSQL, hay "Not Only SQL"

Dù tên gọi vậy, NoSQL không phải "không dùng SQL". Hiểu đúng hơn là "Not Only SQL":

  • Không vứt database quan hệ đi.
  • Thêm option lưu trữ mới vào toolbox.

Với social feed, game log, IoT data, dữ liệu semi-structured hoặc thay đổi nhanh, cần mô hình linh hoạt hơn. MongoDB là đại diện tiêu biểu trong dòng document-oriented database.


Khái niệm cốt lõi: Document và Collection

MongoDB chuyển đơn vị lưu trữ từ row sang document.

Document

Document là đơn vị dữ liệu nhỏ nhất trong MongoDB. Nó giống JSON object, nhưng bên trong dùng BSON (Binary JSON):

  • Format binary, đọc/ghi nhanh hơn.
  • Hỗ trợ kiểu dữ liệu JSON không có (date, binary data...).

Sức mạnh thật sự của document là nesting:

  • Embed object và array trực tiếp.
  • Không cần normalize hết thành nhiều bảng join.

Ví dụ: Document đơn hàng ecommerce

{
  // ID duy nhất, tương đương primary key
  "_id": ObjectId("64b8f1e2a9b3c5d6e7f8a9b0"),

  // Lưu kiểu Date native
  "created_at": ISODate("2024-05-20T09:30:00Z"),
  "status": "Processing",

  // Object nested: không cần bảng address riêng
  "delivery_info": {
    "country": "France",
    "city": "Paris",
    "detail": "Avenue des Champs Elysées"
  },

  // Array các document embedded
  "cart_items": [
    {
      "sku": "KB-MECHANICAL-01",
      "count": 1,
      "unit_price": 599.0
    },
    {
      "sku": "MOUSE-PAD-XL",
      "count": 2,
      "unit_price": 49.5
    }
  ]
}

Ở đây:

  • Metadata đơn hàng, thông tin giao hàng, line items nằm chung một document.
  • Read thường chỉ cần 1 round-trip, phù hợp nhiều use case API.

Collection

Nếu document giống row, thì collection tương đương table.

Khác biệt lớn:

  • Dynamic schema.
  • Document trong cùng collection không cần field giống hệt nhau.

Ví dụ trong collection users:

  • Document này có wechat_id.
  • Document kia chỉ có emailgithub_username.

Độ linh hoạt này giúp data model evolve cùng code mà không cần migration bắt buộc mỗi thay đổi.

Trường _id

Mọi document phải có _id:

  • Làm primary key.
  • Không chỉ định → MongoDB tự sinh ObjectId.
  • ObjectId chứa timestamp, có thể suy ra thời gian tạo từ ID.

CRUD cơ bản trong MongoDB

Giả sử đã connect database (qua mongosh hoặc GUI). Các ví dụ dưới thao tác trên collection employees.

Create: Insert Document

MongoDB cung cấp insertOneinsertMany.

Insert một document

// Thêm nhân viên mới vào collection "employees"
db.employees.insertOne({
  name: "Jack",
  department: "Engineering",
  is_manager: false,
  skills: ["Java", "Docker"],
  onboard_date: new Date()
})

Insert nhiều document

// Thêm nhiều intern cùng lúc
db.employees.insertMany([
  {
    name: "Mike",
    role: "Intern",
    age: 21,
    mentor: "Jack"
  },
  {
    name: "Tommy",
    role: "Intern",
    age: 22,
    mentor: "Jack"
  }
])

Read: Query Document

Dùng findOne cho 1 kết quả, find cho nhiều kết quả.

Tìm một document

// Tìm nhân viên đầu tiên tên "Jack"
db.employees.findOne({ name: "Jack" })

Tìm nhiều document

// Tìm tất cả nhân viên > 21 tuổi
// $gt nghĩa là "greater than"
db.employees.find({ age: { $gt: 21 } })

MongoDB hỗ trợ query language phong phú với operator $lt, $in, $and, $or...


Update: Sửa document hiện có

Update gồm 2 phần:

  • Filter (document nào cần sửa).
  • Update operator (sửa gì), thường là $set.

Update một document

// Thăng chức "Tommy" thành Junior Developer
db.employees.updateOne(
  { name: "Tommy" },                    // Filter
  { $set: { role: "Junior Developer" } } // Update
)

Update nhiều document

// Thêm location mặc định cho nhân viên chưa có field "location"
db.employees.updateMany(
  { location: { $exists: false } }, 
  {
    $set: {
      location: "New York",
      wfh_allowed: true
    }
  }
)

Có thể dùng $inc, $push, $pull cho counter và array manipulation.


Delete: Xóa document

Delete theo pattern query: deleteOnedeleteMany.

Xóa một document

// Xóa nhân viên đầu tiên tên "Mike"
db.employees.deleteOne({ name: "Mike" })

Xóa nhiều document

// Xóa tất cả record intern
db.employees.deleteMany({ role: "Intern" })

⚠️ Cảnh báo:
db.employees.deleteMany({}) với filter rỗng sẽ xóa toàn bộ collection. Cẩn thận khi dùng.


Xây dựng môi trường MongoDB local hiệu quả

Hiểu lý thuyết và CRUD API rồi, bước tiếp là có môi trường local đáng tin cậy.

Dựng database stack thủ công thường khá mệt:

  • Cài MongoDB tay hoặc container.
  • Quản lý multi-version cho các project khác nhau.
  • Xử lý port conflict và data directory.

Nếu làm nhiều service/legacy project, bạn có thể cần:

  • MongoDB 5.x cho app cũ.
  • MongoDB 7.x hoặc 8.x cho service mới.

Chuyển đổi thủ công nhanh thành error-prone.

Lúc này, platform có thể install MongoDB with one click trở nên rất giá trị:

  • Tránh vật lộn với OS installer và script custom.
  • Spin up nhiều instance cô lập theo project.
  • Giữ OS sạch mà vẫn có full local database stack.

Ví dụ, dùng tool coi MongoDB như một phần của dev stack rộng hơn sẽ giúp:

  • Chạy song song các version MongoDB khác nhau (5.0 đến 8.0).
  • Kết hợp MongoDB với MySQL, PostgreSQL, Redis... trong cùng local web dev environment.
  • Quản lý service qua GUI thay vì edit config file và service definition tay.

Kết quả:

  • Ít thời gian setup và dependency management.
  • Nhiều thời gian hơn cho schema design, query writing, feature building.

image.png

Nếu mục tiêu là học sâu MongoDB hoặc integrate vào nhiều project mà không phải đấu installer mỗi lần, việc offload environment orchestration cho tooling và focus vào document model + CRUD logic thường hiệu quả nhất.


Kết luận

Document model của MongoDB không "tốt hơn" hay "kém hơn" relational table – nó là cách biểu diễn dữ liệu khác:

  • Document và collection map tự nhiên với nhiều data structure app hiện đại.
  • Dynamic schema và embedded document tỏa sáng trong domain thay đổi nhanh.
  • CRUD operation biểu cảm mà không đòi migration cứng nhắc từ đầu.

Khi setup MongoDB local dễ như bấm nút thay vì theo hướng dẫn nhiều trang, bạn sẽ dễ experiment với schema thực tế, index, query hơn – nơi MongoDB thật sự phát huy sức mạnh.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí