Từ SQL đến NoSQL
I. Giới thiệu tổng quan: Tại sao mình tìm đến NoSQL và MongoDB?
Chào các bạn, mình là một người đang trên con đường học và làm việc với dữ liệu. Gần đây, trong một dự án cá nhân, mình đã gặp phải một vấn đề khá quen thuộc với những ai đã từng làm việc với cơ sở dữ liệu quan hệ (SQL). Việc phải JOIN
quá nhiều bảng để lấy thông tin hoàn chỉnh cho một đối tượng, ví dụ như profile người dùng, kèm theo đó là cấu trúc dữ liệu thay đổi liên tục khi thêm tính năng mới, đã khiến mình cảm thấy mô hình SQL trở nên cứng nhắc và chậm chạp.
Hãy tưởng tượng, để lấy thông tin của một sinh viên, bạn cần truy vấn bảng Student
để lấy tên, sau đó JOIN
với bảng Mark
để lấy điểm, rồi lại JOIN
với bảng Subject
để biết tên môn học. Mọi thứ trở nên phức tạp rất nhanh. Đó là lúc mình quyết định phải tìm một hướng đi mới, một giải pháp linh hoạt hơn. Và hành trình khám phá thế giới NoSQL, cụ thể là MongoDB, của mình đã bắt đầu từ đó. Bài viết này là những ghi chép, tổng hợp của mình trong quá trình học hỏi, hy vọng sẽ giúp các bạn có một cái nhìn rõ ràng và dễ tiếp cận hơn về chủ đề này.
II. NoSQL là gì?
Trước khi đi sâu vào NoSQL, chúng ta hãy cùng nhắc lại một vài khái niệm cơ bản. Dữ liệu (Data) là một tập hợp thông tin, có thể là số, văn bản, hoặc các loại media khác. Còn Cơ sở dữ liệu (Database) là một bộ sưu tập có tổ chức của các dữ liệu đó, giúp chúng ta dễ dàng truy cập, quản lý và cập nhật. Để quản lý cơ sở dữ liệu, chúng ta cần một
Hệ quản trị cơ sở dữ liệu (DBMS).
Trong một thời gian dài, mô hình thống trị là SQL (Structured Query Language), hay còn gọi là cơ sở dữ liệu quan hệ (RDBMS).
SQL (Cách truyền thống): Mô hình này lưu trữ dữ liệu trong các bảng có cấu trúc chặt chẽ, với các hàng và cột được định nghĩa trước. Mình hay ví von SQL giống như một tủ hồ sơ với các ngăn kéo được dán nhãn cố định. Mọi tài liệu (dữ liệu) phải tuân theo một mẫu định sẵn và được chia nhỏ để cất vào đúng ngăn.
1 Điều này đảm bảo tính nhất quán và toàn vẹn dữ liệu rất tốt.NoSQL (Cách tiếp cận mới): NoSQL, viết tắt của "Not Only SQL" (Không chỉ là SQL), ra đời để giải quyết những hạn chế của SQL. Nó lưu trữ dữ liệu ở định dạng phi bảng (non-tabular).
1 Thay vì chia nhỏ thông tin của một đối tượng ra nhiều bảng, NoSQL có xu hướng lưu trữ tất cả trong một cấu trúc duy nhất. Quay lại với ví dụ tủ hồ sơ, NoSQL giống như một thư mục trên máy tính, nơi mỗi file (document) chứa toàn bộ thông tin liên quan đến một đối tượng, ví dụ như toàn bộ hồ sơ của sinh viên "Anh" nằm gọn trong một file duy nhất.
Sự khác biệt cốt lõi nằm ở Cấu trúc vs. Linh hoạt. SQL thực thi một lược đồ (schema) nghiêm ngặt, trong khi NoSQL cung cấp một lược đồ linh hoạt, cho phép phát triển nhanh hơn và xử lý dữ liệu đa dạng dễ dàng hơn. Tuy nhiên, sự linh hoạt này cũng đi kèm với trách nhiệm. Với NoSQL, ứng dụng của bạn phải đủ thông minh để xử lý các trường hợp dữ liệu không đồng nhất, chẳng hạn một số người dùng có email nhưng một số khác thì không.
III. Khám phá các "họ" trong thế giới NoSQL
Thế giới NoSQL rất đa dạng, không chỉ có một loại duy nhất. Dựa trên cách chúng lưu trữ và truy vấn dữ liệu, chúng ta có thể chia chúng thành một vài "họ" chính.
Key-Value Store: Đây là dạng đơn giản nhất của NoSQL. Dữ liệu được lưu dưới dạng một cặp khóa-giá trị (
key-value
), tương tự như một cấu trúcmap
hayhash table
trong lập trình. Bạn chỉ có thể truy vấn dữ liệu thông quakey
.1 Loại này cực kỳ nhanh và hiệu quả cho các tác vụ như caching (lưu trữ bộ đệm) hay quản lý phiên người dùng (user sessions). "Ngôi sao" sáng giá nhất trong họ này chính là Redis .Graph Database: Đúng như tên gọi, loại cơ sở dữ liệu này được thiết kế để lưu trữ và điều hướng các mối quan hệ. Dữ liệu được biểu diễn dưới dạng các nút (nodes) đại diện cho thực thể và các cạnh (edges) đại diện cho mối quan hệ giữa chúng. Đây là lựa chọn hoàn hảo cho các ứng dụng mạng xã hội (ai là bạn của ai), hệ thống gợi ý (sản phẩm nào liên quan đến sản phẩm nào), hay phát hiện gian lận. Neo4j là cái tên dẫn đầu trong lĩnh vực này.
Document Database: Đây chính là "nhân vật chính" mà chúng ta sẽ tìm hiểu sâu hơn. Cơ sở dữ liệu tài liệu lưu trữ dữ liệu trong các cấu trúc giống như JSON, được gọi là document. Mỗi document chứa các cặp
field-value
và có thể có cấu trúc phức tạp, bao gồm cả các document lồng nhau và mảng. Đây là loại CSDL rất tự nhiên cho các nhà phát triển web và là nền tảng của MongoDB.
Không phải ngẫu nhiên mà chúng ta tập trung vào MongoDB. Dữ liệu từ trang xếp hạng uy tín DB-Engines cho thấy MongoDB là hệ quản trị CSDL NoSQL loại Document phổ biến vượt trội, với điểm số cao hơn hẳn so với các đối thủ trong các loại khác.
Để dễ hình dung, mình đã tổng hợp lại trong bảng sau:
Loại NoSQL | Cấu trúc dữ liệu cốt lõi | Trường hợp sử dụng tiêu biểu | Nổi bật |
Key-Value | Cặp key: value đơn giản | Caching, lưu trữ phiên (session) | Redis |
Graph | Nodes (thực thể) và Edges (quan hệ) | Mạng xã hội, hệ thống gợi ý | Neo4j |
Document | Documents (đối tượng JSON/BSON) | Ứng dụng web, quản lý nội dung | MongoDB |
IV. MongoDB
MongoDB là một cơ sở dữ liệu tài liệu, nơi dữ liệu được tổ chức theo một hệ thống phân cấp đơn giản và trực quan: Database > Collections > Documents.
Document: Là đơn vị lưu trữ cơ bản nhất, tương tự một đối tượng JSON. Mỗi document tự động có một trường
_id
duy nhất để định danh.Collection: Là một nhóm các document, có thể coi như một bảng trong thế giới SQL.
Database: Là nơi chứa các collection.
<Ảnh: Sơ đồ minh họa cấu trúc Database > Collection > Document trong MongoDB>
Điều làm nên sức mạnh của MongoDB chính là sự linh hoạt của Document.
Đa dạng kiểu dữ liệu: MongoDB hỗ trợ nhiều kiểu dữ liệu như số, chuỗi, ngày tháng, mảng, và cả document lồng nhau.
Cấu trúc linh hoạt (Flexible Schema): Bạn có thể dễ dàng lồng một document vào trong một document khác (Nested Document) hoặc lưu trữ một danh sách các giá trị trong một mảng (Array).
Tính đa hình (Polymorphism): Đây là một trong những đặc điểm "ăn tiền" nhất. Các document trong cùng một collection không bắt buộc phải có cấu trúc giống hệt nhau. Một document có thể có trường
phone
, trong khi một document khác thì không.
Tính đa hình này không chỉ là một đặc tính kỹ thuật, nó trực tiếp hỗ trợ cho việc phát triển phần mềm theo phương pháp Agile. Hãy tưởng tượng bạn muốn thêm một tính năng mới, ví dụ như thêm trường "LinkedIn profile" cho người dùng. Với SQL, bạn sẽ phải thực hiện lệnh ALTER TABLE
, một thao tác có thể ảnh hưởng đến hiệu năng và cần được lên kế hoạch cẩn thận. Với MongoDB, bạn chỉ cần cập nhật mã nguồn ứng dụng để bắt đầu thêm trường mới vào các document. Các document cũ không có trường này vẫn hoạt động bình thường. Lược đồ cơ sở dữ liệu có thể tiến hóa nhanh như chính các tính năng của ứng dụng.
V. Cài đặt và kết nối môi trường MongoDB
Giờ là lúc chúng ta bắt tay vào việc. Có nhiều cách để làm việc với MongoDB, nhưng mình sẽ giới thiệu 3 cách phổ biến nhất.
Cách dễ nhất (Cloud-First): MongoDB Atlas
MongoDB Atlas là dịch vụ CSDL trên mây của MongoDB. Nó cho phép bạn tạo một cluster miễn phí để học tập và thử nghiệm mà không cần cài đặt phức tạp.
Bước 1: Tạo tài khoản tại trang chủ của MongoDB Atlas.
Bước 2: Tạo một Free Cluster. Bạn có thể chọn nhà cung cấp đám mây (AWS, Google Cloud, Azure) và khu vực gần bạn nhất.
Bước 3: Tạo một Database User. Đây là tài khoản dùng để kết nối vào CSDL. Nhớ copy và lưu lại password của user nhé, chúng ta sẽ cần nó ngay sau đây!.
Bước 4: Thêm địa chỉ IP của bạn vào IP Access List. Vì lý do bảo mật, Atlas chỉ cho phép kết nối từ những IP được cấp phép. Bạn có thể chọn "Add My Current IP Address" cho tiện.
Cách của Power-User (Local): MongoDB Shell & Tools
Nếu bạn muốn làm việc trực tiếp trên máy tính của mình, bạn cần cài đặt hai thứ:
MongoDB Shell (
mongosh
): Đây là giao diện dòng lệnh để tương tác với CSDL.MongoDB Database Tools: Bộ công cụ giúp bạn import/export dữ liệu (như
mongoimport
,mongoexport
).Sau khi cài đặt, bạn có thể lấy chuỗi kết nối (connection string) từ Atlas và dán vào terminal để kết nối đến cluster trên mây của mình.
Cách trực quan (GUI): MongoDB Compass
Nếu bạn không phải là fan của cmd, MongoDB Compass là một công cụ GUI (Giao diện đồ họa người dùng) tuyệt vời. Nó cho phép bạn xem, sửa, và truy vấn dữ liệu một cách trực quan.
Bước 1: Tải và cài đặt MongoDB Compass từ trang chủ MongoDB.
Bước 2: Trong Atlas, chọn "Connect" và qua tab "Compass".
Bước 3: Copy chuỗi kết nối được cung cấp, dán vào Compass, nhập mật khẩu của database user bạn đã tạo, và nhấn Connect.
VI. Ngôn ngữ truy vấn Mongo (MQL)
Sau khi đã kết nối thành công, giờ là lúc học cách "nói chuyện" với MongoDB bằng Ngôn ngữ Truy vấn Mongo (MQL).
6.1. Quản lý cơ bản (Database & Collections)
Trong mongosh
, bạn có thể dùng các lệnh sau:
show dbs
: Hiển thị tất cả các database.use database_name
: Chuyển sang hoặc tạo mới một database.db.createCollection('collection_name')
: Tạo một collection mới.show collections
: Hiển thị các collection trong database hiện tại.db.collection_name.drop()
: Xóa một collection.db.dropDatabase()
: Xóa toàn bộ database hiện tại (hãy cẩn thận!).
6.2. Thêm dữ liệu (Create)
Để thêm document, chúng ta dùng lệnh insert()
. Bạn có thể thêm một hoặc nhiều document cùng lúc.
db.student.insert({"name":"Thai"})
: Thêm một document.db.student.insert()
: Thêm một mảng các document.Lưu ý cú pháp phải là JSON hợp lệ, các key và value chuỗi phải nằm trong dấu ngoặc kép. Bạn cũng có thể chèn các cấu trúc phức tạp như mảng hay đối tượng lồng nhau.
Để nhập một lượng lớn dữ liệu từ file JSON, bạn có thể dùng công cụ mongoimport.
6.3. Đọc dữ liệu (Read) - Phần Cơ Bản
findOne()
vàfind()
:db.student.findOne()
: Trả về một document đầu tiên nó tìm thấy.db.student.find()
: Trả về một con trỏ (cursor) đến tất cả các document thỏa mãn điều kiện. Bạn cần duyệt qua con trỏ này để xem kết quả.
Bộ lọc (Query Filters): Để tìm kiếm, bạn truyền vào một đối tượng điều kiện. Ví dụ,
db.student.find({"name":"Anh"})
sẽ tìm tất cả sinh viên tên "Anh".Toán tử so sánh: MQL cung cấp các toán tử mạnh mẽ, luôn bắt đầu bằng dấu
$
.$eq
: Bằng (Equal)$ne
: Không bằng (Not Equal)$gt
: Lớn hơn (Greater Than)$gte
: Lớn hơn hoặc bằng$lt
: Nhỏ hơn (Less Than)$lte
: Nhỏ hơn hoặc bằng$in
: Nằm trong một mảng các giá trị$nin: Không nằm trong mảng giá trị
Cú pháp chung là {field: {operator: value}}, ví dụ: db.student.find({"salary": {$lt: 50000}}).
Toán tử logic:
$and
: Kết hợp nhiều điều kiện, tất cả phải đúng.$or
: Kết hợp nhiều điều kiện, chỉ cần một cái đúng.$not
: Phủ định một điều kiện.$nor: Tất cả các điều kiện đều sai.
Ví dụ: db.students.find({$and: [{"age": 20}, {"mark": {$gt: 8.0}}]}).
Một điểm tiện lợi của MQL là bạn có thể thực hiện một phép AND ngầm. Thay vì viết {$and: [{field1: val1}, {field2: val2}]}, bạn có thể viết gọn hơn là {field1: val1, field2: val2}. Kết quả là như nhau nhưng code của bạn sẽ sạch sẽ hơn nhiều.
6.4. Đọc dữ liệu (Read) - Phần Nâng cao
$expr
: Toán tử này cho phép bạn so sánh các trường trong cùng một document. Ví dụ, để tìm các chuyến bay mà sân bay đi và sân bay đến là một, bạn có thể viết:db.routes.find({$expr: {$eq: ["$src_airport", "$dst_airport"]}})
. Dấu$
trước tên trường biến nó thành giá trị của trường đó để so sánh.Toán tử phần tử (Element Operators):
$exists
: Kiểm tra xem một trường có tồn tại hay không. Ví dụ:db.companies.find({"ipo": {$exists: true}})
.$type
: Kiểm tra kiểu dữ liệu của một trường. Ví dụ:db.companies.find({"homepage_url": {$type: 2}})
(kiểm tra xem có phải kiểu String không).1
6.5. Truy vấn các cấu trúc phức tạp
Document lồng nhau: Bạn dùng "dấu chấm" (dot notation) để truy cập vào các trường con. Ví dụ, để tìm các địa chỉ có mã zip là 11385:
db.inspections.find({"address.zip": 11385})
.Mảng:
$all
: Tìm các document mà trường mảng chứa tất cả các phần tử được chỉ định. Ví dụ:db.students.find({skills: {$all: ["math", "english"]}})
.$size
: Tìm các document có trường mảng với kích thước chính xác. Ví dụ:db.students.find({hobbies: {$size: 2}})
.$elemMatch
: Tìm các document có ít nhất một phần tử trong mảng thỏa mãn một bộ điều kiện phức tạp. Ví dụ, tìm học sinh có ít nhất một bài thi (exam) trên 80 điểm:db.grades.find({"scores": {$elemMatch: {"type": "exam", "score": {$gt: 80}}}})
.
6.6. Cập nhật dữ liệu (Update)
Tương tự find
, chúng ta có updateOne()
(cập nhật một document) và updateMany()
(cập nhật nhiều document). Điều quan trọng là sử dụng các toán tử cập nhật để thay đổi dữ liệu thay vì ghi đè toàn bộ document.
$set
: Thay đổi hoặc thêm mới giá trị của một trường.$inc
: Tăng giá trị của một trường số lên một lượng nhất định.$push
: Thêm một phần tử vào cuối một mảng.$unset
: Xóa một trường khỏi document.$rename
: Đổi tên một trường.
6.7. Xóa dữ liệu (Delete)
Rất đơn giản với deleteOne()
và deleteMany()
, nhận vào một đối tượng điều kiện tương tự như find()
.
6.8. Tinh chỉnh kết quả (Result Refinement)
Sau khi find()
, bạn có thể "nối đuôi" các phương thức của con trỏ để xử lý kết quả:
.sort()
: Sắp xếp kết quả (1 cho tăng dần, -1 cho giảm dần)..limit()
: Giới hạn số lượng document trả về..skip()
: Bỏ qua một số lượng document đầu tiên..count()
: Đếm số lượng document trong kết quả.Các phương thức này thường được kết hợp để làm phân trang (pagination).
Cuối cùng là Projection, cho phép bạn chỉ định những trường nào sẽ được trả về trong kết quả. Cú pháp là db.collection.find(query, projection)
. Ví dụ, để chỉ lấy student_id
và class_id
, bạn viết: db.grades.find({}, {"student_id": 1, "class_id": 1})
(số 1 là lấy, số 0 là bỏ). Việc này không chỉ làm kết quả gọn hơn mà còn là một kỹ thuật tối ưu hiệu năng quan trọng. Bằng cách giảm lượng dữ liệu truyền qua mạng, ứng dụng của bạn sẽ nhanh và hiệu quả hơn.
VII. Lời kết: Tổng kết và những bước đi tiếp theo
Vậy là chúng ta đã cùng nhau đi qua một hành trình từ việc hiểu NoSQL là gì, khám phá các loại hình của nó, đi sâu vào MongoDB và thực hành các câu lệnh MQL cơ bản đến nâng cao. Hy vọng những ghi chép này đã giúp bạn hệ thống hóa kiến thức.
Hãy cùng nhìn lại những điểm chính :
NoSQL là "Not Only SQL", một cách tiếp cận linh hoạt, phi quan hệ để lưu trữ dữ liệu.
Có nhiều loại NoSQL như Key-Value, Graph, và Document, mỗi loại phù hợp với một bài toán khác nhau.
MongoDB là một Document Database hàng đầu, với khái niệm cốt lõi là Collections và Documents dạng JSON.
Chúng ta đã học các thao tác CRUD (Create, Read, Update, Delete) và các toán tử mạnh mẽ của MQL để truy vấn và thao tác dữ liệu.
Hành trình của chúng ta mới chỉ bắt đầu. Cách tốt nhất để thành thạo MQL là thực hành. Hãy thử tải về các bộ dữ liệu mẫu mà MongoDB cung cấp (như trong slide 40) và tự mình viết các câu lệnh truy vấn. Đừng ngại thử nghiệm và xem tài liệu chính thức của MongoDB, đó là nguồn kiến thức vô tận. Chúc các bạn thành công!
Nhận xét
Đăng nhận xét