Top 20+ câu hỏi phỏng vấn MongoDB thường gặp

MongoDB đã trở thành một trong những NoSQL Database được sử dụng rộng rãi nhất hiện nay nhờ khả năng mở rộng linh hoạt, lưu trữ dữ liệu dạng tài liệu và hiệu năng cao. Nếu bạn đang chuẩn bị cho buổi phỏng vấn vị trí Backend Developer, Data Engineer, Database Administrator hay bất kỳ công việc nào liên quan đến dữ liệu, việc nắm chắc các câu hỏi xoay quanh MongoDB là bước chuẩn bị vô cùng quan trọng. 

Đọc bài viết này để hiểu rõ hơn về:

  • Các câu hỏi phỏng vấn MongoDB cơ bản
  • Các câu hỏi phỏng vấn MongoDB nâng cao
  • Các câu hỏi phỏng vấn MongoDB dạng bài tập thực hành

Tổng quan về MongoDB

MongoDB là một hệ quản trị cơ sở dữ liệu NoSQL phổ biến, được thiết kế để lưu trữ dữ liệu dạng tài liệu (document-oriented) dưới định dạng BSON (Binary JSON). Không giống các hệ cơ sở dữ liệu quan hệ (RDBMS) như MySQL hay PostgreSQL, MongoDB không yêu cầu schema cố định – điều này giúp lập trình viên dễ dàng mở rộng, thay đổi cấu trúc dữ liệu mà không cần chỉnh sửa toàn bộ bảng.

Một số đặc điểm nổi bật của MongoDB gồm:

  • Linh hoạt về cấu trúc dữ liệu: Mỗi document có thể chứa các trường khác nhau, phù hợp với ứng dụng phát triển nhanh hoặc thay đổi thường xuyên.
  • Hiệu năng cao: Dữ liệu được truy xuất nhanh nhờ cơ chế indexing mạnh mẽ và lưu trữ dạng BSON.
  • Khả năng mở rộng (Scalability): Hỗ trợ horizontal scaling thông qua sharding để phân tán dữ liệu trên nhiều máy chủ.
  • Dễ tích hợp: MongoDB hoạt động tốt với các ngôn ngữ như Node.js, Python, Java, .NET…
  • Hỗ trợ mạnh cho Big Data & Analytics: Thông qua Aggregation Framework, Atlas và tích hợp tốt với các công cụ như Spark.

MongoDB thường được dùng trong:

  • Các ứng dụng web và mobile có dữ liệu linh hoạt.
  • Hệ thống IoT, real-time analytics, AI/ML pipelines.
  • Các sản phẩm cần scalability cao và thay đổi cấu trúc nhanh như e-commerce, mạng xã hội, content management systems (CMS), hay quản lý nội dung.
  • Product catalogs với các thuộc tính đa dạng
  • Session storage và caching
  • Logging và event tracking
  • Lưu hồ sơ người dùng, sở thích, lịch sử tương tác để cá nhân hoá trải nghiệm

Ngoài ra, bạn có thể tìm hiểu kỹ hơn về MongoDB là gì.

Câu hỏi phỏng vấn MongoDB cấp độ cơ bản

Hãy trình bày các thành phần của MongoDB

MongoDB gồm các thành phần cơ bản sau:

  • Document: là đơn vị dữ liệu cơ bản trong MongoDB, lưu ở dạng BSON (Binary JSON). Mỗi document là một “bản ghi” tự mô tả, có thể lồng (embedded) các document/array khác, có kích thước tối đa 16MB.

Khóa đặc biệt: _id (duy nhất trong collection được tự động index).

Ví dụ:

{
  "_id": "usr_1001",
  "name": { "first": "An", "last": "Nguyen" },
  "email": "an@example.com",
  "roles": ["admin", "editor"],
  "profile": {
    "dob": "1999-10-21",
    "phones": [{ "type": "mobile", "number": "+84-912-xxx-xxx" }]
  },
  "active": true,
  "createdAt": ISODate("2025-12-07T05:00:00Z")
}
  • Field: Mỗi trường (key) trong document, đi kèm giá trị (value). Document trong cùng một collection không bắt buộc có cùng tập field (schema linh hoạt), tên field phân biệt hoa thường (case-sensitive).

Kiểu dữ liệu phổ biến: string, number, boolean, date, array, object, ObjectId, Decimal128, Binary, Timestamp, Null, Regular Expression, JavaScript Code …

Ví dụ: name, email, roles (array), profile (object), active (boolean).

  • Collection: Tập hợp nhiều document có liên quan (tương tự “bảng” trong SQL nhưng không yêu cầu schema). Một database có nhiều collection; collection có thể tạo index, validator, collation, …

Ví dụ: users, orders, products.

  • Database: Chứa nhiều collection, mỗi MongoDB instance có thể có nhiều database.

Database mặc định: admin (quản trị), local (replica set), config (sharding metadata).

Ví dụ: ecommerce_db, user_management, analytics_db.

MongoDB khác gì với các RDBMS khác?

Tiêu chíMongoDB (NoSQL)RDBMS (MySQL, PostgreSQL, …)
Mô hình dữ liệuDạng document (BSON) linh hoạt, không cần schema cố địnhDạng bảng (table) với schema cứng (phải định nghĩa cột, kiểu dữ liệu)
Cấu trúc dữ liệuDocument gồm các field-value, có thể lồng nhau (nested, array, object)Bảng gồm hàng và cột; các bảng liên kết bằng khóa ngoại (foreign key)
Ngôn ngữ truy vấnMongoDB Query Language (MQL) – cú pháp JSONSQL có cú pháp chuẩn, dùng SELECT, JOIN, GROUP BY…
Tính linh hoạt (Schema)Schema linh hoạt – mỗi document có thể khác nhauSchema cố định, mọi bản ghi phải tuân thủ cùng cấu trúc
Mối quan hệ dữ liệuKhông hỗ trợ join phức tạp; có thể dùng $lookup hoặc embedded documentsHỗ trợ JOIN nhiều bảng để kết nối dữ liệu quan hệ
Khả năng mở rộng (Scalability)Mở rộng theo chiều ngang (horizontal scaling) thông qua sharding, nghĩa là chia dữ liệu sang nhiều server dễ dàngMở rộng theo chiều dọc (vertical scaling), nghĩa là tăng tài nguyên phần cứng cho 1 server là chính
Hiệu năngTruy xuất nhanh với dữ liệu lớn, không cần join, phù hợp với hệ thống thiên về đọc (read-heavy workload)Có thể chậm hơn nếu join hoặc subquery nhiều, nhưng tối ưu tốt cho các truy vấn phức tạp
Giao dịch (Transaction)Hỗ trợ transactions trên nhiều document từ MongoDB 4.0, đảm bảo ACID compliance Hỗ trợ transaction mạnh mẽ và nhất quán ACID từ lâu
Tính nhất quán (Consistency)Theo mô hình BASE (Basically Available, Soft state, Eventual consistency), nhưng có thể cấu hình độ nhất quán mạnh (strong consistency) thông qua read concernwrite concern. với read/write concernTheo mô hình ACID (Atomicity, Consistency, Isolation, Durability)
Ứng dụngHệ thống big data, real-time analytics, IoT, ứng dụng linh hoạt, quản lý nội dung, product catalogsHệ thống ngân hàng, tài chính, kế toán, yêu cầu tính toàn vẹn cao
Cấu trúc lưu trữLưu trữ dưới dạng collection chứa các document BSONLưu trữ dưới dạng bảng, hàng, cột
Công cụ hỗ trợCó Aggregation Framework, Change Streams, Atlas, Spark Connector để xử lý và phân tích dữ liệu lớnCó Stored Procedures, Triggers, Views, Joins và các công cụ tối ưu truy vấn truyền thống.

BSON là gì và tại sao MongoDB dùng BSON thay vì JSON thuần?

BSON (Binary JSON) là định dạng nhị phân được MongoDB dùng để lưu trữ và truyền dữ liệu.

Nói đơn giản, BSON là phiên bản “nâng cấp” của JSON, được thiết kế để máy tính đọc nhanh hơn, ghi nhanh hơn và linh hoạt hơn trong việc xử lý dữ liệu. Ví dụ một document trong MongoDB mà bạn thấy như thế này (dạng JSON):

{
  "name": "An Nguyen",
  "age": 25,
  "skills": ["Node.js", "MongoDB", "Python"],
  "joinedAt": "2024-10-05T10:00:00Z"
}

Khi được lưu trong cơ sở dữ liệu, MongoDB chuyển đổi nó thành dạng BSON, để tối ưu tốc độ đọc-ghi và tiết kiệm không gian lưu trữ.

Tại sao MongoDB dùng BSON thay vì JSON thuần?

Lý doGiải thích
1. Hiệu năng cao hơnBSON được lưu ở dạng nhị phân, nên máy tính đọc nhanh hơn nhiều so với văn bản JSON (vì không cần parse từng ký tự), và có thể traverse document mà không cần parse toàn bộ.
2. Hỗ trợ nhiều kiểu dữ liệu hơnJSON chỉ hỗ trợ string, number, boolean, array, object. Còn BSON hỗ trợ thêm các kiểu như Date, Binary, ObjectId, Decimal128, Timestamp, …
3. Tính toàn vẹn và định vị nhanhBSON lưu thêm thông tin độ dài và kiểu dữ liệu, giúp MongoDB truy cập từng trường nhanh mà không phải đọc hết document, cho phép skip và seek hiệu quả
4. Tối ưu cho lưu trữ và networkVì là dạng nhị phân nén, BSON gọn nhẹ hơn, giúp giảm dung lượng và tăng tốc độ truyền tải qua mạng. Lưu ý: BSON không phải luôn nhỏ hơn JSON, đôi khi có thể lớn hơn do metadata.
5. Dễ mở rộng trong tương laiBSON được thiết kế có thể thêm kiểu dữ liệu mới mà không làm mất tương thích với định dạng cũ.

find()findOne() khác nhau như thế nào?

Trong MongoDB, cả find() và findOne() đều dùng để truy vấn dữ liệu, nhưng khác nhau ở số lượng kết quả trả về và cách sử dụng như sau:

HàmMục đíchKết quả trả vềKhi nào nên dùng?
find()Dùng để lấy nhiều document phù hợp với điều kiện.Trả về con trỏ (cursor) và có thể duyệt qua nhiều kết quả, hỗ trợ pagination với limit(), skip(), sort()Khi bạn cần danh sách dữ liệu (ví dụ: tất cả người dùng trên 18 tuổi).
findOne()Dùng để lấy một document duy nhất phù hợp với điều kiện.Trả về document đầu tiên tìm thấy (hoặc null nếu không có), không trả về cursor.Khi bạn chỉ cần một bản ghi cụ thể (ví dụ: tìm người dùng theo email), hiệu năng cao hơn khi chỉ cần 1 kết quả.

Giả sử ta có collection users như sau:

[
  { "name": "An", "age": 25, "city": "Hanoi" },
  { "name": "Binh", "age": 30, "city": "Hanoi" },
  { "name": "Cuong", "age": 22, "city": "Da Nang" }
]

Sử dụng find() để tìm những người sống ở Hà Nội với cú pháp:

db.users.find({ city: "Hanoi" })

=> Kết quả trả về tất cả người sống ở Hà Nội:

[
  { "name": "An", "age": 25, "city": "Hanoi" },
  { "name": "Binh", "age": 30, "city": "Hanoi" }
]

Còn sử dụng findOne() với cú pháp db.users.findOne({ city: "Hanoi" }) sẽ trả về kết quả như sau:

{ "name": "An", "age": 25, "city": "Hanoi" }

_id trong MongoDB là gì? Vai trò của _id trong các document của MongoDB là gì?

Trong MongoDB, mỗi document đều có một trường đặc biệt tên là _id, dùng để xác định duy nhất bản ghi đó trong một collection. Ta có thể coi _id giống như khóa chính (primary key) trong cơ sở dữ liệu quan hệ (RDBMS). Id có các đặc điểm như sau:

  • Mỗi document bắt buộc phải có _id, nếu bạn không tự tạo, MongoDB sẽ tự động tự tạo.
  • Mỗi _id là duy nhất trong một collection, giúp đảm bảo không có hai document trùng nhau.
  • MongoDB tự tạo index mặc định trên trường _id, nên việc tìm kiếm bằng _id luôn rất nhanh.
  • _id có thể là bất kỳ kiểu dữ liệu nào (string, number, ObjectId, UUID…) miễn là unique.
  • _id là immutable – không thể thay đổi sau khi document được tạo (trừ khi xóa và tạo lại).

Theo mặc định, _id được MongoDB tạo dưới dạng ObjectId, là một chuỗi 12 byte chứa:

  • 4 byte đầu: thời gian tạo (timestamp) – tính bằng giây từ Unix epoch
  • 5 byte tiếp: mã máy (machine ID)
  • 3 byte cuối: bộ đếm tự tăng (counter) – đảm bảo tính duy nhất trong cùng một giây

Ví dụ:

{
  "_id": ObjectId("6753e5d9a12c4f0045e2e7d9"),
  "name": "An Nguyen",
  "email": "an@example.com"
}

=> Từ ObjectId này, ta có thể suy ra thời điểm document được tạo (dựa trên phần timestamp ở đầu mã) bằng phương thức getTimestamp(): ObjectId(“6753e5d9a12c4f0045e2e7d9”).getTimestamp().

Khi nào “database” thực sự được tạo? 

Trong MongoDB, database không được tạo ngay khi bạn gõ lệnh use <tên_database>, mà chỉ thực sự được tạo ra khi có dữ liệu bên trong. Lệnh use chỉ chuyển môi trường làm việc hiện tại sang database đó, chứ chưa tạo ra database thật. Ví dụ:

use shopDB

MongoDB lúc này chưa tạo ra “shopDB” trong hệ thống vì chưa có collection hoặc document nào. Database chỉ được tạo thực tế khi ta: 

  • Thêm dữ liệu (dùng insertOne(), insertMany(), …), hoặc
  • Tạo collection thủ công bằng db.createCollection().

Ví dụ:

use shopDB
db.products.insertOne({ name: "T-Shirt", price: 199000 })

=> Ngay khi document đầu tiên được thêm, MongoDB sẽ tạo ra shopDB và collection products.

Bên cạnh đó, ta cũng có thể tạo database thông qua lệnh tạo collection:

use shopDB
db.createCollection("products")

Lưu ý: Để kiểm tra database đã được tạo thực sự, dùng lệnh show dbs. Khi đó chỉ những database có dữ liệu mới xuất hiện trong danh sách.

MongoDB lưu trữ hình ảnh và video dung lượng lớn như thế nào?

MongoDB không lưu trực tiếp toàn bộ file lớn trong một document, mà sử dụng một cơ chế đặc biệt gọi là GridFS để chia nhỏ file thành nhiều phần và lưu vào các collection riêng. Nhờ đó, MongoDB có thể xử lý, truyền tải và quản lý dữ liệu đa phương tiện (ảnh, video, PDF…) hiệu quả hơn – đặc biệt phù hợp với các ứng dụng web, cloud storage, hoặc video streaming.

Trong đó, GridFS (Grid File System) là hệ thống lưu trữ file lớn của MongoDB, được thiết kế để xử lý các tệp có kích thước vượt quá giới hạn 16MB/document. Thay vì lưu cả file vào một document, GridFS chia nhỏ file thành nhiều phần (chunk), mỗi phần có kích thước mặc định 255 KB và lưu từng phần đó vào collection riêng. MongoDB sẽ tạo hai collection cho mỗi file:

  • fs.files → chứa thông tin metadata (tên, kích thước, loại file, …)
  • fs.chunks → chứa dữ liệu nhị phân đã được chia nhỏ (các phần của file), mỗi chunk có trường files_id tham chiếu đến document trong fs.files

Để hiểu đơn giản thì giả sử ta có video 50MB:

  • MongoDB chia video thành nhiều mảnh 255 KB (khoảng 200 chunks).
  • Lưu từng mảnh đó vào fs.chunks với trường n đánh số thứ tự chunk (0, 1, 2,…).
  • Lưu thông tin file gốc (tên, số chunk, loại file, MD5 hash …) vào fs.files.
  • Khi cần đọc lại, MongoDB ghép các chunk theo thứ tự để trả về file hoàn chỉnh, hỗ trợ streaming và đọc từng phần (range requests).

Câu hỏi phỏng vấn MongoDB cấp độ nâng cao

Replica Set & High Availability trong MongoDB là gì?

  • Replica Set:  Trong MongoDB, Replica Set là tập hợp nhiều máy chủ (node) cùng lưu trữ bản sao của cùng một dữ liệu. Mục đích là để đảm bảo dữ liệu luôn an toàn và hệ thống luôn sẵn sàng, ngay cả khi một máy chủ gặp sự cố. Một Replica Set thường gồm:
    • Primary: máy chủ chính, nơi thực hiện các thao tác ghi (write) và đọc mặc định, chỉ có duy nhất 1 Primary trong một Replica Set
    • Secondary: một hoặc nhiều máy chủ sao chép dữ liệu từ Primary theo thời gian thực bằng cách đọc oplog (operation log)
    • Arbiter (tuỳ chọn): node chỉ tham gia bầu chọn khi cần chọn Primary mới, nhưng không lưu dữ liệu.

Giả sử ta có 3 server trong một Replica Set gồm 1 Primary và 2 Secondary, nếu Primary bị lỗi hoặc mất kết nối, MongoDB sẽ tự động bầu một Secondary mới làm Primary. Vì vậy ứng dụng vẫn hoạt động, người dùng không bị gián đoạn và dữ liệu vẫn được bảo toàn.

  • High Availability: High Availability (HA) nghĩa là hệ thống luôn hoạt động ổn định, không ngừng trệ, dù có lỗi phần cứng, mất mạng hay downtime. Replica Set chính là cách MongoDB đạt được High Availability thông qua:
    • Tự động sao lưu (replication) dữ liệu giữa các node.
    • Tự động failover khi có sự cố với thời gian chuyển đổi thường < 12 giây.
    • Không cần can thiệp thủ công để khôi phục hoạt động.
    • Read scaling bằng cách phân tải đọc sang Secondary nodes.

=> Tóm lại, Replica Set trong MongoDB giúp đảm bảo High Availability bằng cách duy trì nhiều bản sao dữ liệu trên các node khác nhau. Nếu Primary gặp sự cố, một Secondary sẽ tự động được bầu làm Primary mới, nhờ đó hệ thống liên tục hoạt động, không mất dữ liệu và không downtime.

Hãy trình bày về khái niệm Sharding và khi nào nên sử dụng?

Sharding là cơ chế chia nhỏ dữ liệu (partitioning) của MongoDB, cho phép phân tán dữ liệu ra nhiều máy chủ khác nhau thay vì lưu toàn bộ trong một server duy nhất. Mục tiêu của Sharding là giúp MongoDB có thể xử lý khối lượng dữ liệu cực lớn và tăng hiệu năng truy vấn khi hệ thống phát triển. Nói đơn giản hơn là nếu dữ liệu quá nhiều khiến một server “quá tải”, MongoDB sẽ chia dữ liệu thành nhiều phần nhỏ (shard) và phân phối chúng sang nhiều máy khác nhau. Khi bật Sharding, MongoDB sẽ có ba thành phần chính:

  • Shard: Nơi lưu trữ dữ liệu thật sự, mỗi shard chứa một phần của toàn bộ dataset. Mỗi shard nên là một Replica Set để đảm bảo high availability.
  • Config Server: Lưu thông tin cấu hình và bản đồ phân phối dữ liệu giữa các shard (metadata về shard key ranges, chunk distribution). Cũng nên chạy dưới dạng Replica Set (CSRS – Config Server Replica Set).
  • Query Router (mongos): Tiếp nhận truy vấn từ ứng dụng, xác định dữ liệu nằm ở shard nào và gửi yêu cầu đến shard đó, sau đó merge kết quả trả về cho client

Ví dụ ta có một collection users có 100 triệu bản ghi thì MongoDB có thể chia thành 3 shard:

  • Shard 1 chứa user ở khu vực châu Á
  • Shard 2 chứa user ở châu Âu
  • Shard 3 chứa user ở Mỹ

Vậy những trường hợp nào thì dùng Sharding?

  • Khi dữ liệu quá lớn để lưu trên một server duy nhất: Nếu dung lượng dữ liệu vượt quá khả năng lưu trữ hoặc xử lý của một máy chủ, Sharding giúp chia nhỏ dữ liệu thành nhiều phần (shard) và phân phối sang nhiều máy khác nhau. Nhờ đó, ta có thể mở rộng hệ thống theo chiều ngang (horizontal scaling) dễ dàng chỉ bằng cách thêm server mới.
  • Khi hệ thống cần xử lý lượng truy vấn và ghi dữ liệu khổng lồ: Trong các ứng dụng có lượng người dùng lớn (ví dụ: mạng xã hội, sàn thương mại điện tử), mỗi giây có thể có hàng nghìn truy vấn đọc/ghi. Sharding cho phép nhiều server xử lý song song, từ đó giúp tăng tốc độ phản hồi và tránh nghẽn cổ chai (bottleneck).
  • Khi dữ liệu được phân bố theo khu vực địa lý: Nếu ứng dụng của bạn có người dùng ở nhiều quốc gia (ví dụ: châu Á, châu Âu, Mỹ), ta có thể phân chia dữ liệu theo khu vực (region-based sharding). Lợi ích sẽ là giúp truy vấn của người dùng được xử lý gần với vị trí họ hơn, từ đó giảm độ trễ (latency) và tăng trải nghiệm người dùng.
  • Khi cần mở rộng hệ thống theo từng giai đoạn (scale-out): Với Sharding, bạn không cần thay đổi cấu trúc ứng dụng, chỉ cần thêm máy chủ mới (shard) để chứa thêm dữ liệu. Điều này giúp mở rộng linh hoạt, phù hợp với các hệ thống phát triển nhanh mà vẫn muốn tiết kiệm chi phí ban đầu.
  • Khi hiệu suất truy vấn giảm dần do dữ liệu quá lớn: Nếu bạn nhận thấy các truy vấn ngày càng chậm vì lượng dữ liệu tăng lên, Sharding có thể giúp phân tán workload giữa nhiều máy. Vì mỗi shard chỉ xử lý một phần dữ liệu nên sẽ giúp giảm tải, tăng hiệu năng và tối ưu chỉ mục (index).

MongoDB giải quyết concurrency control như thế nào?

Concurrency Control (kiểm soát truy cập đồng thời) là cơ chế giúp nhiều người hoặc nhiều tiến trình có thể đọc và ghi dữ liệu cùng lúc mà không gây xung đột hoặc sai lệch dữ liệu. Nói một cách dễ hiểu là khi có nhiều người cùng thao tác trên cùng một dữ liệu ví dụ như hai người cùng chỉnh sửa hồ sơ khách hàng hoặc cùng cập nhật số dư tài khoản thì Concurrency Control sẽ đảm bảo các thay đổi diễn ra theo trật tự hợp lý, để kết quả cuối cùng luôn chính xác. Nếu không có Concurrency Control, hai thay đổi này có thể “đè” lên nhau, khiến hệ thống lưu sai dữ liệu hoặc mất thông tin.

Hãy trình bày về Transaction & Write Concern / Read Preference trong môi trường phân tán

Trong môi trường cơ sở dữ liệu phân tán (distributed environment), dữ liệu có thể được lưu trữ trên nhiều máy chủ (node) khác nhau để tăng hiệu năng và độ tin cậy. Vì vậy, MongoDB cung cấp các cơ chế như Transaction, Write Concern và Read Preference để đảm bảo dữ liệu luôn chính xác và đồng bộ dù hệ thống hoạt động trên nhiều node.

Transaction – Giao dịch đảm bảo tính toàn vẹn dữ liệu

Transaction (giao dịch) cho phép gộp nhiều thao tác ghi (write) thành một khối logic duy nhất, và đảm bảo “hoặc tất cả thao tác đều thành công, hoặc tất cả bị hủy (rollback) nếu có lỗi”. Nhờ vậy mà MongoDB có thể duy trì các tính ACID (Atomicity, Consistency, Isolation, Durability) tương tự các hệ SQL truyền thống. Ví dụ khi chuyển tiền giữa hai tài khoản:

session.startTransaction();
db.accounts.updateOne({ name: "A" }, { $inc: { balance: -100 } });
db.accounts.updateOne({ name: "B" }, { $inc: { balance: +100 } });
session.commitTransaction();

=> Nếu một thao tác thất bại, toàn bộ giao dịch sẽ bị rollback để dữ liệu không bị sai lệch.

Lưu ý về Transactions:

  • Từ MongoDB 4.0: hỗ trợ multi-document transactions trong replica sets
  • Từ MongoDB 4.2: hỗ trợ distributed transactions trong sharded clusters
  • Transactions có overhead về performance – chỉ dùng khi cần thiết
  • Timeout mặc định: 60 giây (có thể cấu hình)

Write Concern – Mức độ đảm bảo khi ghi dữ liệu

Write Concern xác định mức độ xác nhận (acknowledgment) mà MongoDB cần nhận được sau khi ghi dữ liệu. 

Cấu hìnhÝ nghĩa
{ w: 1 }Ghi thành công khi Primary xác nhận. (Nhanh nhưng ít an toàn)
{ w: "majority" }Chờ đa số node trong Replica Set xác nhận. (An toàn cao hơn, chậm hơn một chút)
{ w: 0 }Không cần xác nhận. (Hiệu năng cao, nhưng rủi ro mất dữ liệu)
{ w: 2 }Chờ Primary + ít nhất 1 Secondary xác nhận
{ w: 3 }Chờ Primary + ít nhất 2 Secondary xác nhận

Trong hệ thống phân tán, Write Concern giúp cân bằng giữa tốc độ ghi và độ an toàn. Và nếu hệ thống yêu cầu độ tin cậy cao như giao dịch tài chính thì nên dùng w: “majority”.

Read Preference – Lựa chọn nơi đọc dữ liệu

Trong Replica Set, dữ liệu được lưu ở nhiều node (Primary và Secondary). Read Preference cho phép bạn chọn đọc dữ liệu từ đâu tùy vào mục tiêu hiệu năng hoặc tính nhất quán. Còn trong hệ thống phân tán, Read Preference giúp cân bằng tải (load balancing) và giảm độ trễ (latency) khi người dùng ở nhiều khu vực địa lý khác nhau.

Chế độMô tả
primaryLuôn đọc từ Primary nên dữ liệu luôn mới nhất, giúp đảm bảo nhất quán.
secondaryĐọc từ Secondary nên giúp giảm tải cho Primary, nhưng có thể đọc dữ liệu stale (chưa được replicate đầy đủ).
primaryPreferredƯu tiên Primary, nếu không có thì đọc Secondary. Tốt cho high availability.
secondaryPreferredƯu tiên Secondary, nếu không có thì đọc Primary. Tốt cho read-heavy workload.
nearestĐọc từ node gần nhất (tính theo độ trễ mạng). Tốt cho ứng dụng phân tán đa khu vực (geo-distributed applications).

Trong môi trường phân tán, Transaction đảm bảo tính toàn vẹn dữ liệu, Write Concern kiểm soát độ tin cậy khi ghi và Read Preference tối ưu nơi đọc dữ liệu. Ba cơ chế này phối hợp giúp MongoDB vừa an toàn, vừa linh hoạt và hiệu năng cao ngay cả khi chạy trên nhiều máy chủ khắp thế giới.

Hãy so sánh Aggregation Pipeline và MapReduce trong MongoDB

Tiêu chíAggregation PipelineMapReduce
Khái niệmLà cơ chế xử lý dữ liệu theo chuỗi các giai đoạn (pipeline). Mỗi giai đoạn thực hiện một tác vụ như lọc ($match), gom nhóm ($group), tính toán ($sum, $avg), sắp xếp ($sort)…Là mô hình xử lý dữ liệu truyền thống gồm hai hàm JavaScript: map() (dữ liệu key–value) và reduce() (tổng hợp kết quả theo key).
Cách hoạt độngDữ liệu được chuyển qua từng stage theo thứ tự → kết quả của stage này là đầu vào của stage sau.MongoDB sẽ chạy các hàm JavaScript trên mỗi document → thu kết quả từ hàm map()→ tổng hợp lại bằng reduce().
Ngôn ngữ & cú phápDùng cú pháp native MongoDB, gần với JSON nên dễ đọc và dễ viết.Dùng JavaScript functions, phải viết nhiều code thủ công hơn.
Hiệu năng xử lýRất nhanh vì được chạy trong engine C++ của MongoDB, tận dụng index và tối ưu bộ nhớ.Chậm hơn vì chạy qua JavaScript interpreter, tốn tài nguyên CPU và RAM.
Khả năng song song hóa (Parallelism)Được MongoDB tối ưu tự động nên các stages có thể chạy song song nội bộ.Hỗ trợ song song hóa nhưng ít tối ưu, phụ thuộc vào script người viết.
Khả năng mở rộngRất tốt, có thể kết hợp $merge, $out để xử lý batch lớn hoặc xuất kết quả ra collection.Có thể xử lý dữ liệu lớn nhưng hiệu năng kém và không tối ưu khi mở rộng.
Tính linh hoạtĐủ mạnh cho hầu hết các bài toán tổng hợp, và còn hỗ trợ viết logic JS qua $function hoặc $accumulator.Linh hoạt cao vì cho phép viết logic JavaScript tùy ý, nhưng phải đánh đổi hiệu năng.
Ứng dụng phổ biếnBáo cáo, dashboard, phân tích dữ liệu real-time, tính toán thống kê, ETL nhẹ.Xử lý dữ liệu phức tạp hoặc yêu cầu thao tác đặc biệt bằng JavaScript (trước khi Aggregation ra đời).
Giới hạn & hạn chếGiới hạn document 16MB, 1000 stages, 100MB bộ nhớ (có thể tăng bằng allowDiskUse: true).Rất tốn tài nguyên, không phù hợp cho production lớn, dễ làm chậm hệ thống.
Khả năng bảo trì & debugCấu trúc dạng pipeline dễ đọc, dễ bảo trì, dễ test từng giai đoạn.Code JavaScript khó debug và bảo trì hơn, đặc biệt khi logic phức tạp.
Trạng thái hiện tạiLà chuẩn hiện nay, được MongoDB liên tục cải tiến và khuyến nghị sử dụng.Đã bị deprecated (không khuyến khích dùng) từ MongoDB 5.0, bị remove hoàn toàn từ MongoDB 6.0+.
Tổng kếtNhanh hơn, nhẹ hơn, dễ dùng và an toàn cho production.Linh hoạt hơn nhưng chậm, phức tạp và đã lỗi thời.

Hãy trình bày các loại Index nâng cao trong MongoDB (Compound, Multikey, TTL, Text, Geospatial) và những trường hợp sử dụng

Loại IndexChức năngỨng dụngVí dụ minh họa
Compound IndexKết hợp nhiều trường (fields) trong một index duy nhất.Khi truy vấn thường xuyên sử dụng nhiều điều kiện trên nhiều trường. Giúp MongoDB dùng một index thay vì phải tạo nhiều index riêng.js db.users.createIndex({ age: 1, city: 1 }) 
→ Tối ưu cho truy vấn: db.users.find({ age: 25, city: "Hanoi" })
Multikey IndexTự động được tạo khi index hóa mảng (array). Mỗi phần tử trong mảng được index riêng biệt.Khi field chứa danh sách giá trị như tags, categories, skills,…js db.products.createIndex({ tags: 1 }) 
→ Giúp tìm nhanh các sản phẩm có tags chứa “electronics”.
TTL Index (Time To Live)Tự động xóa document sau một thời gian nhất định.Khi lưu dữ liệu tạm thời như logs, session, token, cache,…js db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 }) 
→ Document sẽ bị xóa sau 1 giờ.
Background task chạy mỗi 60 giây để cleanup.
Text IndexCho phép tìm kiếm toàn văn (full-text search)trong các chuỗi văn bản.Khi cần tìm kiếm nội dung theo từ khóa trong các trường văn bản. Hỗ trợ stemming, stop words, scoring.js db.articles.createIndex({ content: "text", title: "text" }) 
→ Dùng cho: db.articles.find({ $text: { $search: "mongodb index" } })
Geospatial IndexHỗ trợ truy vấn vị trí địa lý (location-based queries).Khi ứng dụng liên quan đến bản đồ, khoảng cách, vị trí, như tìm quán ăn gần nhất. Hai loại: 2d (flat), 2dsphere (hình cầu – khuyến khích).js db.places.createIndex({ location: "2dsphere" })
→ Tìm điểm gần vị trí người dùng: $near, $geoWithin

Giả sử hệ thống MongoDB của bạn bắt đầu xử lý chậm khi dữ liệu tăng lên, bạn sẽ làm gì để tối ưu hiệu năng truy vấn?

Để tối ưu hóa truy vấn trong MongoDB, ta sẽ đi theo hướng phân tích – tối ưu – kiểm chứng.

Cụ thể, có một số kỹ thuật quan trọng sau:

  • Tạo và sử dụng Index hợp lý

Index là công cụ quan trọng nhất giúp MongoDB truy cập dữ liệu nhanh hơn. Nếu không có index, hệ thống sẽ phải quét toàn bộ collection (COLLSCAN), gây tốn thời gian và tài nguyên. Một số phương pháp tối ưu index là:

  • Tạo index trên các trường thường được dùng trong điều kiện lọc (find), sắp xếp (sort), hoặc join ($lookup).
  • Dùng compound index khi truy vấn nhiều trường cùng lúc.
  • Tránh tạo quá nhiều index (mỗi index tốn RAM và làm chậm thao tác ghi).
  • Xóa các indexes không sử dụng bằng cách theo dõi mức sử dụng với $indexStats.
  • Kiểm tra truy vấn có dùng index không bằng lệnh:
db.users.find({ age: 25, city: "Hanoi" }).explain("executionStats")

=> Nếu kết quả hiển thị IXSCAN, nghĩa là truy vấn đã sử dụng index thành công.

  • Giới hạn dữ liệu trả về (Projection)

MongoDB cho phép chỉ định rõ những trường cần lấy, giúp giảm kích thước dữ liệu và thời gian xử lý. Ví dụ:

db.users.find({}, { name: 1, email: 1 })

=> Thay vì lấy toàn bộ document, chỉ hai trường name và email được trả về, tiết kiệm băng thông và bộ nhớ RAM.

Lưu ý: Sử dụng _id: 0 để loại bỏ _id nếu không cần, vì _id luôn được trả về mặc định.

  • Viết Aggregation Pipeline hiệu quả

Aggregation là công cụ mạnh để xử lý và tổng hợp dữ liệu, nhưng nếu viết sai cách sẽ làm chậm hiệu năng. Một số mẹo tối ưu aggregation gồm:

  • Đặt $match$project ở đầu pipeline để lọc và giới hạn dữ liệu sớm.
  • Tránh $unwind trên các mảng lớn nếu không cần thiết.
  • Sử dụng tùy chọn allowDiskUse: true để cho phép MongoDB ghi tạm ra đĩa khi dữ liệu quá lớn. vượt quá 100MB per stage.
  • Sử dụng $limit sau $sort để giảm số documents cần sort.
  • Tận dụng indexes cho $match và $sort ở đầu pipeline.
  • Tránh $lookup trong vòng lặp lớn – cân nhắc denormalization.

MongoDB Atlas là gì và nó khác gì so với MongoDB tự triển khai?

MongoDB Atlas là nền tảng Database-as-a-Service (DBaaS) do chính MongoDB Inc. cung cấp, cho phép người dùng triển khai, quản lý và mở rộng cơ sở dữ liệu MongoDB trực tiếp trên nền tảng đám mây mà không cần cài đặt thủ công. Atlas có thể chạy trên nhiều nền tảng đám mây phổ biến như:

  • AWS (Amazon Web Services)
  • Google Cloud Platform (GCP)
  • Microsoft Azure

Điểm khác biệt giữa MongoDB Atlas và MongoDB tự triển khai (Self-Hosted MongoDB)

Tiêu chíMongoDB Atlas (Cloud)Self-Hosted MongoDB
Cách triển khaiTự động triển khai chỉ với vài cú click trên giao diện web. Không cần cấu hình máy chủ.Cần cài đặt thủ công trên máy chủ (local hoặc server riêng).
Quản lý hệ thốngĐược MongoDB Atlas quản lý toàn bộ (backup, cập nhật, mở rộng, bảo mật), OS patching, nâng cấp phiên bản MongoDB.Người dùng tự chịu trách nhiệm quản trị, sao lưu, bảo mật và nâng cấp.
Bảo mậtTích hợp sẵn SSL, IP Whitelisting, và quản lý truy cập nâng cao (IAM), encryption at rest, LDAP/Kerberos authentication.Phải tự cấu hình bảo mật, tường lửa, xác thực và quyền truy cập.
Khả năng mở rộng (Scalability)Tự động scale up/down chỉ bằng vài thao tác, auto-scaling clusters, triển khai đa khu vực.Phải cấu hình thủ công khi cần mở rộng hệ thống.
Chi phíTính phí dựa trên tài nguyên và mức sử dụng (Pay-as-you-go). Có gói miễn phí để thử nghiệm.Chi phí thấp hơn nếu tự quản lý, nhưng tốn công vận hành và bảo trì.
Giám sát & hiệu năngCó sẵn công cụ Atlas Dashboard để giám sát hiệu năng, cảnh báo lỗi, và phân tích truy vấn.Phải cài thêm công cụ như mongostat, mongotop, hoặc giải pháp monitoring riêng.
Tích hợp & AutomationHỗ trợ sẵn chức năng backup tự động, global cluster, trigger (serverless functions).Phải tự viết script hoặc cài thêm công cụ để tự động hóa.

Khi nào nên dùng từng loại?

Tình huốngGiải pháp phù hợp
Dự án nhỏ, demo, học tập hoặc startup cần chạy nhanh, không tốn thời gian setupMongoDB Atlas (dùng free tier M0)
Doanh nghiệp muốn môi trường production ổn định, có backup và bảo mật cao, tập trung vào business logic thay vì infrastructureMongoDB Atlas
Dự án nội bộ, yêu cầu chạy offline hoặc có hạ tầng riêng (on-premises), có yêu cầu tuân thủ về vị trí lưu trữ dữ liệu (data residency compliance)Self-Hosted MongoDB
Khi muốn toàn quyền kiểm soát cấu hình và chi phí phần cứng, có team DevOps mạnhSelf-Hosted MongoDB

MongoDB Query-Based Interview Questions – Bài tập thực hành

Giả sử ta có 5 collection: users, products, orders, articles, places.

// users
[
  { _id: 1, name: "An",   email: "an@ex.com",   age: 25, city: "Hanoi",   skills: ["node", "mongo"], createdAt: ISODate("2025-01-01") },
  { _id: 2, name: "Binh", email: "binh@ex.com", age: 32, city: "Hanoi",   skills: ["python"],        createdAt: ISODate("2025-01-10") },
  { _id: 3, name: "Cuong",email: "cuong@ex.com",age: 22, city: "Da Nang", skills: ["node"],           createdAt: ISODate("2025-02-01") }
]

// products
[
  { _id: 101, name: "Laptop A", price: 1200, category: "electronics", tags: ["laptop","computer"], inStock: true },
  { _id: 102, name: "Phone B",  price: 800,  category: "electronics", tags: ["phone","mobile"],     inStock: true },
  { _id: 103, name: "Shirt C",  price: 40,   category: "fashion",     tags: ["shirt","men"],        inStock: false }
]

// orders
[
  { _id: 10001, userId: 1, status: "completed", items: [{ productId: 101, qty: 1 }], total: 1200, orderedAt: ISODate("2025-03-01") },
  { _id: 10002, userId: 1, status: "pending",   items: [{ productId: 102, qty: 2 }], total: 1600, orderedAt: ISODate("2025-03-05") },
  { _id: 10003, userId: 2, status: "completed", items: [{ productId: 103, qty: 3 }], total: 120,  orderedAt: ISODate("2025-03-10") }
]

// articles
[
  { _id: "a1", title: "MongoDB Indexing Best Practices", content: "Compound, multikey, TTL...", tags: ["mongodb","index"] },
  { _id: "a2", title: "Text Search in MongoDB",          content: "How to use $text ...",      tags: ["mongodb","text"]  }
]

// places (GeoJSON)
[
  { _id: "p1", name: "Pho 24",   category: "food",    location: { type: "Point", coordinates: [106.700, 10.776] } },
  { _id: "p2", name: "Cafe ABC", category: "coffee",  location: { type: "Point", coordinates: [106.702, 10.778] } },
  { _id: "p3", name: "Park XYZ", category: "park",    location: { type: "Point", coordinates: [106.710, 10.770] } }
]

1. CRUD cơ bản + Projection + Sort

Yêu cầu: Lấy danh sách người dùng ở Hanoi, chỉ trả về name và email, sắp xếp name tăng dần, giới hạn 2 kết quả.

=> Query:

db.users.find(
  { city: "Hanoi" },
  { _id: 0, name: 1, email: 1 }
).sort({ name: 1 }).limit(2)

Trong đó:

  • Dùng projection để giảm dữ liệu trả về.
  • sort + limit giúp hiển thị gọn và nhanh (phù hợp UI phân trang).
  • _id: 0 loại bỏ field _id khỏi kết quả.

2. Truy vấn mảng (Multikey) & Toán tử so khớp

Yêu cầu: Tìm user có skill “node”.

=> Query: 

db.users.find({ skills: "node" })

Trong đó:

  • Field skills là mảng → multikey index (nếu tạo) sẽ index từng phần tử.
  • So khớp trực tiếp "node" là đủ (không cần $in).

=> Tối ưu: Tạo index db.users.createIndex({ skills: 1 }) nếu truy vấn này phổ biến.

3. Update có điều kiện + Array Operators

Yêu cầu: orders._id=10002 đổi status sang "completed" và tăng qty của mọi item thêm 1

=> Query:

db.orders.updateOne(
  { _id: 10002 },
  {
    $set: { status: "completed" },
    $inc: { "items.$[].qty": 1 }   // $[] = all array elements
  }
)

Trong đó:

  • $[] áp dụng cho tất cả phần tử mảng.

4. Aggregation: Lọc sớm → Gom nhóm → Sắp xếp → Top-K

Yêu cầu: Tổng doanh thu (total) theo userId cho các đơn "completed", lấy Top 2.

=> Pipeline:

db.orders.aggregate([
  { $match: { status: "completed" } },               // lọc sớm
  { $group: { _id: "$userId", revenue: { $sum: "$total" } } },
  { $sort: { revenue: -1 } },
  { $limit: 2 }
])

Trong đó:

  • Đặt $match đầu pipeline để giảm dữ liệu đi qua các stage sau (tối ưu hiệu năng).

5. $lookup (giống JOIN) + $unwind + $project

Yêu cầu: Lấy chi tiết đơn hàng 10001 kèm tên sản phẩm của từng item.

=> Pipeline:

db.orders.aggregate([
  { $match: { _id: 10001 } },
  { $unwind: "$items" },
  { $lookup: {
      from: "products",
      localField: "items.productId",
      foreignField: "_id",
      as: "prod"
  }},
  { $unwind: "$prod" },
  { $project: {
      _id: 0,
      orderId: "$_id",
      productName: "$prod.name",
      qty: "$items.qty",
      lineTotal: { $multiply: ["$prod.price", "$items.qty"] }
  }}
])

Trong đó:

  • $lookup “nối” dữ liệu giữa collection.
  • $unwind biến mỗi item thành 1 dòng để tính lineTotal.
  • $project giúp trả về đúng thông tin cần.

6. Text Search + Score

Yêu cầu: Tìm bài viết có chứa “mongodb index”, ưu tiên score cao.

Chuẩn bị index:

db.articles.createIndex({ title: "text", content: "text" })

Query:

db.articles.find(
  { $text: { $search: "mongodb index" } },
  { score: { $meta: "textScore" }, title: 1 }
).sort({ score: { $meta: "textScore" } })

Trong đó:

  • Text index chỉ có 1 trên mỗi collection (nhưng gồm nhiều field).
  • $meta: "textScore" để lấy và sắp xếp theo độ phù hợp.

7. Geospatial: tìm địa điểm

Yêu cầu: Tìm quán trong bán kính 2km quanh tọa độ [106.700, 10.776].

Chuẩn bị index:

db.places.createIndex({ location: "2dsphere" })

Query:

db.places.find({
  location: {
    $near: {
      $geometry: { type: "Point", coordinates: [106.700, 10.776] },
      $maxDistance: 2000
    }
  }
})

Trong đó:

  • 2dsphere cho tọa độ thật (kinh độ/vĩ độ) , hỗ trợ GeoJSON.
  • $near tự sắp xếp theo độ gần; rất hữu ích cho app bản đồ.

8. Index + .explain() (tối ưu hiệu năng):

Yêu cầu: Truy vấn sản phẩm theo category + price tăng dần. Tạo index phù hợp và kiểm tra.

Index gợi ý:

db.products.createIndex({ category: 1, price: 1 })

Query:

db.products.find(
  { category: "electronics" }
).sort({ price: 1 }).explain("executionStats")

Trong đó:

  • Compound index (category→price) “cover” cả lọc và sort nên sẽ tránh được in-memory sort.
  • explain() cho biết có IXSCAN (tốt) hay COLLSCAN (cần tối ưu).

9. Mini-Transaction (2 cập nhật nhất quán)

Yêu cầu: Trừ 100 từ tài khoản A, cộng 100 vào tài khoản B trong một transaction.

=> Query:

const session = db.getMongo().startSession();
session.startTransaction();
try {
  const acc = session.getDatabase("shop").collection("accounts");
  acc.updateOne({ _id: "A" }, { $inc: { balance: -100 } });
  acc.updateOne({ _id: "B" }, { $inc: { balance:  100 } });
  session.commitTransaction();
} catch (e) {
  session.abortTransaction();
  throw e;
} finally {
  session.endSession();
}

Trong đó:

  • Transaction đảm bảo atomicity: hoặc cả hai cập nhật thành công, hoặc rollback. 
  • Phải truyền (pass) đối tượng session vào tất cả các thao tác trong transaction.

Tổng kết

MongoDB không chỉ là một cơ sở dữ liệu NoSQL thông thường  mà là một công cụ mạnh mẽ cho các ứng dụng hiện đại cần xử lý dữ liệu linh hoạt, quy mô lớn và tốc độ cao. Việc chuẩn bị thật tốt các lý thuyết, thực hành cũng như luyện tập trước các câu hỏi sẽ giúp bạn trả lời tự tin trong mọi vòng phỏng vấn kỹ thuật. ITviec hy vọng bài viết trên đã cung cấp cho bạn những kiến thức bổ ích giúp bạn chuẩn bị thật tốt cho các cơ hội nghề nghiệp nhé.

TÁC GIẢ
Nhat Anh
Nhat Anh

Content Writer

Gần một năm sản xuất nội dung mạng xã hội trong lĩnh vực IT, Ánh tập trung khai thác các chủ đề công nghệ theo cách trực quan, dễ tiếp cận. Đặc biệt là các xu hướng mới, nghiên cứu công cụ và kiến thức nền tảng,... Các bài viết của Ánh hướng đến việc giúp người đọc nhanh chóng nắm bắt và ứng dụng kiến thức hiệu quả.