Tải bản đầy đủ (.doc) (29 trang)

BÀI TẬP LỚN CƠ SỞ DỮ LIỆU NÂNG CAO TÌM HIỂU VỀ MONGO DB

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (404.21 KB, 29 trang )

TRƯỜNG ĐH CÔNG NGHỆ - ĐH QUỐC GIA HÀ NỘI
KHOA CÔNG NGHỆ THÔNG TIN
  
CƠ SỞ DỮ LIỆU NÂNG CAO
Đề tài:
TÌM HIỂU VỀ MONGO DB
GV hướng dẫn: PGS.TS. Nguyễn Hà Nam
HV thực hiện: Trần Thị Then – K18
Ngô Thị Nga – K18
HÀ NỘI, 2012
2
MỤC LỤC
1 ĐẶT VẤN ĐỀ 4
2 TỔNG QUAN VỀ NOSQL 4
3 HỆ QUẢN TRỊ CƠ SỞ DỮ LIỆU MONGODB 5
3.1 Giới thiệu 5
3.2 Các đặc điểm của Mongo 6
3.3 Văn bản BSON 6
3.4 Ngôn ngữ truy vấn của MongoDB 8
3.4.1 Thiết kế lược đồ 10
3.4.2 Chỉ mục 12
3.4.3 Sao chép dữ liệu 16
3.4.4 Truy vấn 18
3.4.5 GridFS 19
4 KẾT LUẬN 21
5 PHỤ LỤC A. HƯỚNG DẪN CÀI ĐẶT 22
6 PHỤ LỤC B. MỘT SỐ CÚ PHÁP CÂU LỆNH 24
3
1 ĐẶT VẤN ĐỀ
Với sự phát triển không ngừng của ngành công nghệ thông tin. Khối dữ liệu cần xử
lý trong các ứng dụng là rất lớn. Đặc biệt là sự bùng nổ công nghệ Web 2.0, nơi các mạng


dịch vụ dữ liệu cộng đồng cho phép người dùng tự do tạo nội dung trên web, dẫn đến dữ
liệu tăng lên rất nhanh, vượt qua giới hạn xử lý của các Hệ quản trị cơ sở dữ liệu quan hệ
truyền thống. Để đáp ứng được nhu cầu phát triển của xã hội, đòi hỏi một cơ sở dữ liệu
(CSDL) có thể lưu trữ, xử lý được một lượng dữ liệu lớn một cách nhanh chóng và hiệu
quả. NoSQL đã ra đời, thay thế hệ quản trị CSDL quan hệ, giải quyết bài toán trên.
Tác giả viết tài liệu này với mục đích giúp người đọc bước đầu tiếp cận, có cái nhìn
khái quát về các CSDL hiện đại NoSQL; hiểu chi tiết hơn hệ cơ sở dữ liệu cơ bản của
NoSQL là MongoDB; đồng thời giúp người đọc có thể thực hiện một ứng dụng cơ bản
trên hệ cơ sở dữ liệu MongoDB.
2 TỔNG QUAN VỀ NOSQL
Với hầu hết các thời kỳ web, Hệ quản trị cơ sở dữ liệu quan hệ dựa trên SQL đã
thống trị hầu hết các hệ Quản trị Cơ sở dữ liệu. Tuy nhiên, thời gian gần đây, một cách
tiếp cận mới đã bắt đầu biết đến là NoSQL, tạo ra sự thay thế cho các hệ quản trị cơ sở dữ
liệu quan hệ truyền thống.
NoSQL còn có nghĩa là Non-Relational - không ràng buộc. Tuy nhiên, thuật ngữ đó
ít phổ dụng hơn và ngày nay người ta thường dịch NoSQL thành Not Only SQL - Không
chỉ SQL. NoSQL ám chỉ đến những cơ sở dữ liệu không dùng mô hình dữ liệu quan hệ
để quản lý dữ liệu trong lĩnh vực phần mềm
Thuật ngữ NoSQL được giới thiệu lần đầu vào năm 1998 sử dụng làm tên gọi chung
cho các cơ sở dữ liệu quan hệ nguồn mở nhỏ nhưng không sử dụng SQL cho truy vấn.
Vào năm 2009, Eric Evans, nhân viên của Rackspace giới thiệu lại thuật ngữ NoSQL
khi Johan Oskarsson của Last.fm muốn tổ chức một hội thảo về cơ sở dữ liệu nguồn mở
phân tán. Thuật ngữ NoSQL đánh dấu bước phát triển của thế hệ CSDL mới: một thế hệ
CSDL không ràng buộc, phân tán, nguồn mở, khả năng mở rộng theo chiều ngang, có thể
lưu trữ, xử lý từ một lượng rất nhỏ cho tới hàng petabytes dữ liệu trong hệ thống có độ
chịu tải, chịu lỗi cao với những đòi hỏi về tài nguyên phần cứng thấp.
Một số đặc điểm nhận dạng cho thế hệ CSDL mới này bao gồm: schema-free, hỗ trợ
mở rộng dễ dàng, API đơn giản, nhất quán cuối (eventual consistency), không giới hạn
không gian dữ liệu,
Sau đây là danh sách các CSDL NoSQL:

1. Wide Column Store / Column Families: Hadoop/HBase – Apache, BigTable –
Google, Cassandra - Facebook/Apache, Hypertable - Zvents Inc/Baidu, Cloudera,
SciDB, Mnesia, Tablets,…
2. Key-Value Store/Tuple store
4
a. Key/value cache in RAM: memcached, Citrusleaf database, Velocity, Redis,
Tuple space,
b. Key/value save on disk: Memcachedb, Berkeley DB, Tokyo Cabinet, Redis,
c. Eventually Consistent Key Value Store: Amazon Dynamo, Voldemort,
Dynomite, KAI, Cassandra, Hibari, Project Voldemort,…
d. Ordered key-value store: NMDB, Memcachedb, Berkeley DB,
e. Distributed systems: Apache River, MEMBASE, Azure Table Storage, Amazon
Dynamo,
3. Document Store: Apache Jackrabbit, CouchDB, IBM Lotus Notes Storage Format
(NSF), MongoDB, Terrastore, ThruDB, OrientDB, RavenDB,
4. Graph Database: Neo4J, Sones, AllegroGraph, Core Data, DEX, FlockDB,
InfoGrid, OpenLink Virtuoso,
Tuy cùng mang những đặc điểm chung của NoSQL nhưng mỗi CSDL NoSQL cũng
có những đặc điểm riêng, và vì thế thường được dùng cho những dự án khác nhau. Ví dụ:
MongoDB và Redis là những lựa chọn tốt cho việc lưu trữ các dữ liệu thống kê ít
được đọc mà lại được viết thường xuyên.
Hadoop, một CSDL dạng tự do, phân tán làm tốt công việc lưu trữ các dữ liệu lớn
như các con số thống kê thời tiết hoặc công việc phân tích nghiệp vụ.
Memcachedb, một CSDL nhất thời chóng tàn, tuyệt vời trong lưu trữ các phiên làm
việc web, các khóa, và các con số thống kê ngắn hạn.
Cassandra và Riak (các lưu trữ dư thừa, tự động tạo bó cluster) làm tốt trong các môi
trường với các ứng dụng có tính sẵn sàng cao, khi thời gian sống tối đa là sống còn.
Để tìm hiểu sâu hơn về các CSDL hiện đại NoSQL, chúng ta đi nghiên cứu chi tiết
một CSDL đặc trưng là MongoDB.
3 HỆ QUẢN TRỊ CƠ SỞ DỮ LIỆU MONGODB

3.1 Giới thiệu
Hệ cơ sở dữ liệu Mongo được phát triển bởi công ty 10gen từ năm 2007, khi công
ty này xây dựng một Platform as a Service tương tự như ứng dụng Google App Engine.
Trong năm 2009, hệ cơ sở dữ liệu Mongo đã được phát triển như một phần mềm nguồn
mở độc lập, có giấy phép của AGPL.
Từ phiên bản 1.4 được phát hành vào tháng 3 năm 2011, hệ cơ sở dữ liệu Mongo
đã phát hành rộng rãi ngoài thị trường. Cho tới thời điểm hiện tại thì 10gen đã cho phát
hành phiên bản 2.0.3 là một phiên bản nâng cấp và hoàn thiện hơn. Hệ cơ sở dữ liệu này
đang ngày càng được phát triển hơn để đưa ra những tiện ích hoàn thiện hơn cho người sử
dụng.
Tên hệ cơ sở dữ liệu Mongo bắt nguồn từ một từ tiếng Anh là “humongous” có
nghĩa là rất lớn hay khổng lồ.
5
Mongo là một hệ cơ sở dữ liệu kiểu NoSQL – Not only SQL – không đơn thuần
chỉ là SQL mà đây là một hệ cơ sở dữ liệu ứng dụng cho các dữ liệu lớn, không cần cấu
trúc.
Mongo hỗ trợ các hệ điều hành: Windows, Linux, Mac OS, Solaris với các phiên
bản 32 bit và 64 bit. Ngoài ra Mongo còn cung cấp mã nguồn để cho các nhà phát triển
khác có thể sử dụng. Với các phiên bản 32 bit thì Mongo hỗ trợ khoảng 2.5 Gb dữ liệu.
Hiện tại Mongo đã hỗ trợ các ngôn ngữ lập trình: C, C++, Erlang, Haskell, Java,
Javascript, .NET (C# F#, PowerShell,…), Perl, PHP, Python, Ruby, Scala.
Ngoài ra, cộng đồng phát triển Mongo cũng hỗ trợ thêm một số ngôn ngữ khác nữa
như LISP, Delphi, Erlang, MatLab, Prolog, Objective C, Smalltalk, …
3.2 Các đặc điểm của Mongo
- Cơ sở dữ liệu hướng văn bản
• Các đối tượng tương tự như kiểu dữ liệu của các ngôn ngữ lập trình
• Các văn bản và mảng được nhúng trong cơ sở dữ liệu làm giảm việc phải sử
dụng các phép join – nối
• Kiểu động, không lược đồ
• Không nối và cũng không có các giao tác giữa nhiều đối tượng. Điều này làm

tăng hiệu suất và dễ dùng hơn với các dữ liệu lớn.
- Hiệu suất cao
• Không có phép nối và nhúng dữ liệu làm cho việc đọc và ghi dữ liệu nhanh
hơn.
• Đánh chỉ mục bằng khóa của các văn bản và mảng nhúng
- Tính sẵn sàng cao
• Kết nối nhanh với server
- Tính dễ thay đổi
• Tự động phân vùng dữ liệu trong server: đọc và ghi dữ liệu phân tán trên các
mảnh khác nhau; không dùng phép nối hay thực hiện giao tác đa văn bản làm
cho việc phân tán các truy vấn dễ dàng và nhanh
• Các dữ liệu phân tán trên các server khác nhau, giúp cho việc đọc dữ liệu nhanh
hơn.
• Ngôn ngữ truy vấn dễ sử dụng
3.3 Văn bản BSON
BSON là cách mã hóa các dữ liệu dưới dạng nhị phân với các cặp khóa/ giá trị
được lưu trong một thực thể đơn. BSON hỗ trợ nhúng các văn bản và mảng vào trong các
văn bản và mảng khác. BSON cũng chứa các phần mở rộng cho phép thể hiện nhiều kiểu
dữ liệu khác nhau.
6
Mongo sẽ chuyển các dữ liệu của mình thành các dạng BSON - tức là dạng nhị
phân, sau đó lưu các dữ liệu dạng nhị phân này vào trong CSDL.
BSON được sử dụng bởi ba lý do sau:
1) Đơn giản, nhẹ: Giữ cho không gian lưu trữ dữ liệu là nhỏ nhất, điều này đặc biệt quan
trọng khi mà chuyển dữ liệu qua mạng.
2) Dễ chuyển(Traversable) : BSON được thiết kế để chuyển một cách dễ dàng. Đây là
một đặc tính quan trọng trong việc thể hiện dữ liệu cho MongoDB
3) Hiệu quả: Việc mã hóa và giải mã các dữ liệu dạng BSON có thể được thực hiện một
cách nhanh chóng trong hầu hết các ngôn ngữ dùng cùng kiểu dữ liệu giống ngôn ngữ
C.

Các kiểu cơ bản:
byte 1 byte (8-bits)
int32 4 bytes (32-bit signed interger)
int64 8 bytes (64-bit signed interger)
double8 bytes (64-bit IEEE 754 floating point)
Một số kiểu dữ liệu khác: Cách biểu diễn của nó tương tự với cách biểu diễn ngữ
nghĩa của ngôn ngữ C, có thể dùng "\x01" để biểu diễn cho 0000 0001, hay là dùng toán
tử * để thể hiện việc lặp lại 0 hay nhiều lần một thể hiện( "\x01"*2 biểu diễn cho
"\x01\x01" )
document ::= int32 e_list "\x00" BSON Document
e_list ::= element e_list Sequence of elements
| ""
element ::= "\x01" e_name double Floating point
| "\x02" e_name string UTF-8 string
| "\x03" e_name document Embedded document
| "\x04" e_name document Array
| "\x05" e_name binary Binary data
| "\x06" e_name Undefined — Deprecated
| "\x07" e_name (byte*12) ObjectId
| "\x08" e_name "\x00" Boolean "false"
| "\x08" e_name "\x01" Boolean "true"
| "\x09" e_name int64 UTC datetime
| "\x0A" e_name Null value
7
| "\x0B" e_name cstring cstring Regular expression
| "\x0C" e_name string (byte*12) DBPointer — Deprecated
| "\x0D" e_name string JavaScript code
| "\x0E" e_name string Symbol
e_name ::= cstring Key name
string ::= int32 (byte*) "\x00" String

cstring ::= (byte*) "\x00" CString
binary ::= int32 subtype (byte*) Binary
Ví dụ mã hóa cặp khóa/ giá trị:
{"hello": "world"}→ "\x16\x00\x00\x00\x02hello\x00
\x06\x00\x00\x00world\x00\x00"
3.4 Ngôn ngữ truy vấn của MongoDB
Để dễ hình dung hơn các đặc điểm của MongoDB, ta hãy xem bảng so sánh
tương ứng giữa SQL và Mongo như sau:
Về mặt khái niệm:
SQL Mongo
database database
table collection
index index
partition shard
partition key shard key
row BSON document
column BSON field
join embedding và linking
primary key _id field
group by aggregation
8
Về mặt cú pháp câu lệnh (Chi tiết xem thêm phụ lục B)
CREATE TABLE USERS (a
Number, b Number)
db.createCollection("mycoll")
ALTER TABLE users ADD không có
INSERT INTO USERS
VALUES(3,5)
db.users.insert({a:3,b:5})
SELECT a,b FROM users db.users.find({}, {a:1,b:1})

SELECT * FROM users db.users.find()
SELECT * FROM users WHERE
age=33
db.users.find({age:33})
SELECT a,b FROM users WHERE
age=33
db.users.find({age:33}, {a:1,b:1})
SELECT * FROM users WHERE
age=33 ORDER BY name
db.users.find({age:33}).sort({name:1})
… …
Trước khi đi vào tìm hiểu kỹ hơn về MongoDB, chúng ta làm quen với một số khái
niệm cơ bản của MongoDB:
Văn bản
Văn bản là một khái niệm quan trọng trong MongoDB. Văn bản bao gồm tập hợp
các khóa với các giá trị tương ứng.
Ví dụ: {"greeting" : "Hello, world!"}
Văn bản trên gồm một khóa là “greeting”, với giá trị là “Hello, world!”. Các văn bản
có thể chứa nhiều cặp khóa/giá trị.
Ví dụ: {"greeting" : "Hello, world!", "foo" : 3}
Một số lưu ý:
- Các cặp khóa/ giá trị trong văn bản được sắp xếp. Văn bản trên sẽ khác với văn
bản sau
9
{"foo" : 3, "greeting" : "Hello, world!"}
- Khóa trong văn bản là một chuỗi
- MongoDB phân biệt chữ hoa chữ thường
- Văn bản trong MongoDB không được chứa những khóa giống nhau. Ví dụ văn bản
sau là không hợp lệ
{"greeting" : "Hello, world!", "greeting" : "Hello, MongoDB!"}

Bộ sưu tập
Bộ sưu tập là một nhóm các văn bản. Nếu văn bản tương đương với dòng trong
CSDL quan hệ thì bộ sưu tập tương đương với bảng.
Bộ sưu tập là một Schema-Free, nghĩa là các văn bản có hình dạng khác nhau có thể
cùng được lưu trữ trong 1 bộ sưu tập.
Ví dụ các văn bản sau có thể cùng được lưu trong một bộ sưu tập:
{"greeting" : "Hello, world!"}
{"foo" : 5}
Bộ sưu tập được xác định bởi tên của nó là một chuỗi UTF-8
3.4.1 Thiết kế lược đồ
Với MongoDB, chúng ta ít phải “chuẩn hóa” hơn so với khi làm việc với lược đồ
quan hệ vì trong MongoDB không có khái niệm liên kết (join). Nói chung, với mỗi đối
tượng (object) mức cao nhất, ta sẽ có một bộ sưu tập (collection) dữ liệu.
Một bộ sưu tập không phải cho tất cả các lớp (class), thay vào đó, các đối tượng sẽ
được nhúng vào đó.
Hình 5.1 minh họa có 2 bộ sưu tập: students và courses. Các văn bản student được
nhúng văn bản address và văn bản score. Trong đó, văn bản Score được tham chiếu đến
Courses.
10
Hình 5.1 . Minh họa bộ sưu tập
So sánh với lược đồ quan hệ: ta cần lưu Score vào bảng riêng và dùng khóa ngoài
liên kết với Student.
3.4.1.1 Nhúng và tham thiếu
Một câu hỏi quan trọng trong thiết kế lược đồ Mongo là: “Đối tượng này có cần một
bộ sưu tập của riêng nó không hay nên nhúng vào trong các đối tượng trong các bộ sưu
tập khác?” Trong cơ sở dữ liệu quan hệ, mỗi tiểu mục có thể trở thành một bảng riêng
biệt. Trong Mongo, nó không được khuyến cáo, việc nhúng các đối tượng hiệu quả hơn
nhiều. Chúng ta cũng có thể đặt ra câu hỏi “Tại sao tôi không muốn nhúng đối tượng
này?”
Tại sao tham chiếu lại chậm. Ta xem ví dụ sau. Chúng ta có một đối tượng Student

và cần thực hiện:
print( students.address.city );
Phép toán này sẽ luôn được thực hiện nhanh nếu Address là một đối tượng nhúng, và
được lưu ở RAM nếu Student được lưu ở RAM.
Tuy nhiên, với truy vấn:
print( students.scores[0].for_course.name );
Nếu đó là lần đầu truy cập đến khóa này thì trình tiện ích phải thực hiện truy vấn:
students.scores[0].for_course = db.courses.findOne({_id:_course_id_to_find_});
Các luật cơ bản
- Các đối tượng “lớp thứ nhất” là các đối tượng ở mức cao nhất, có bộ sưu tập của
riêng mình.
11
- Các đối tượng miêu tả chi tiết các mục thường được nhúng
- Các đối tượng mà theo mô hình đối tượng có chứa quan hệ nói chung nên được
nhúng
- Quan hệ nhiều – nhiều thường được tham chiếu.
- Các bộ sưu tập chỉ với một vài đối tượng có thể tồn tại một cách an toàn giống
như bộ sưu tập riêng lẻ, được lưu trữ nhanh chóng trong bộ nhớ máy chủ ứng dụng.
- Các đối tượng nhúng khó khăn để tham chiếu hơn là các đối tượng mức cao.
- Sẽ khó khăn hơn để có một cái nhìn mức hệ thống đối với các đối tượng nhúng.
Ví dụ: Sẽ dễ thực hiện truy vấn tìm 100 sinh viên có điểm cao nhất hơn nếu Score không
bị nhúng.
- Nếu dữ liệu được nhúng lớn, có thể đạt đến giới hạn kích thước của một đối
tượng.
- Nếu hiệu suất là quan trọng, hãy nhúng.
Một số ví dụ
- Customer/Order/ Order Line-Item: Customers, Orders nên có một bộ sưu tập riêng.
Line-Items nên là một mảng các mục cần mua và được nhúng trong đối tượng Order
- Hệ thống Blog: Posts cần có bộ sưu tập riêng. Post Author có thể có bộ sưu tập riêng
hoặc nếu đơn giản chỉ là địa chỉ mail của tác giả thì cho thành một trường trong Posts.

Comments được nhúng trong Posts
3.4.1.2 Lựa chọn chỉ mục
Một khía cạnh thứ hai khi thiết kế lược đồ là việc lựa chọn chỉ mục. Việc đánh chỉ
mục làm cho việc thực hiện truy vấn nhanh hơn. Một truy vấn bình thường cần vài phút,
có thể được thực hiện ngay lập tức với việc sử dụng chỉ mục.
Trong MongoDB:
- Trường _id được đánh chỉ mục tự động
- Những trường mà theo đó các khóa được tìm kiếm nên được đánh chỉ mục
- Những trường sắp xếp nói chung nên được đánh chỉ mục
Lưu ý rằng việc thêm vào chỉ mục chỉ làm chậm quá trình ghi vào bộ sưu tập mà không
làm chậm quá trình đọc. Vì vậy, sử dụng nhiều chỉ mục với những bộ sưu tập mà tỉ lệ
read:write cao. Với những bộ sưu tập mà ghi nhiều hơn đọc, sử dụng chỉ mục là rất tốn
kém.
3.4.2 Chỉ mục
Chỉ mục làm tăng hiệu suất truy vấn lên rất nhiều. Điều quan trọng là nghĩ xem xét tất cả
các loại truy vấn cần trong ứng dụng để xác định những chỉ mục liên quan. Khi đã xác
định xong, việc tạo ra các chỉ mục trong MongoDB là khá dễ dàng.
12
3.4.2.1 Các khái niệm cơ bản
Chỉ mục là một cấu trúc dữ liệu, thu thập thông tin về giá trị của các trường trong
các văn bản của một bộ sưu tập. Cấu trúc dữ liệu này được sử dụng trong tối ưu truy vấn
Mongo để sắp xếp nhanh các văn bản trong một bộ sưu tập.
Chúng ta có thể khởi tạo chỉ mục bằng cách gọi hàm ensureIndex() và cung cấp một
văn bản với một hoặc nhiều khóa để đánh chỉ mục. Ví dụ đánh chỉ mục cho trường name
trong students
db.students.ensureIndex({name:1});
Hàm ensureIndex() chỉ khởi tạo chỉ mục nếu nó chưa tồn tại. Để kiểm tra việc tồn tại
chỉ mục trên bộ sưu tập students, ta có thể dùng hàm: b.students.getIndexes().
Khi một bộ sưu tập được đánh chỉ mục trên một khóa nào đó, truy cập ngẫu nhiên
trên biểu thức truy vấn có chứa khóa đó sẽ được thực hiện rất nhanh. Nếu không được

đánh chỉ mục, MongoDB phải soát tất cả các văn bản để kiểm tra giá trị của khóa đó trong
truy vấn.
Chỉ mục mặc định
Một chỉ mục luôn luôn được tạo ra là _id. Chỉ mục này là đặc biệt và không thể bị
xóa. Chỉ mục _id là duy nhất cho các khóa của nó.
Các khóa nhúng
Với MongoDB chúng ta thậm chí có thể đánh chỉ mục trên các khóa bên trong văn
bản nhúng. Ví dụ:
db.students.ensureIndex({"address.city": 1})
Văn bản như là khóa
Các trường được đánh chỉ mục có thể là bất kỳ loại nào, bao gồm cả văn bản.
Mảng
Khi giá trị của trường được đánh chỉ mục của văn bản là một mảng. MongoDB đánh
chỉ mục mỗi phần tử của mảng đó.
3.4.2.2 Chỉ mục hỗn hợp các khóa
Ngoài chỉ mục khóa đơn, MongoDB còn hỗ trợ đánh chỉ mục hỗn hợp nhiều khóa.
Giống như đánh chỉ mục cơ bản, chúng ta sử dụng hàm ensureIndex() để khởi tạo chỉ
mục.
db.things.ensureIndex({j:1, name:-1});
Khi khởi tạo một chỉ mục, số đi cùng với khóa là hướng của chỉ mục, 1: tăng dần, -1:
giảm dần. Hướng không ảnh hưởng đến việc truy cập ngẫu nhiên nhưng quan trọng nếu
bạn đang làm các truy vấn sắp xếp hoặc phân loại trên chỉ mục hỗn hợp.
13
Nếu chúng ta có một chỉ mục hỗn hợp trên nhiều trường, chúng ta có thể sử dụng nó
để truy vấn trên các tập hợp con đầu của các trường đó. Ví dụ ta có chỉ mục trên (a, b, c),
ta có thể sử dụng nó để truy vấn trên (a), (a, b), (a, b, c).
3.4.2.3 Chỉ mục thưa thớt
Chỉ mục thưa thớt là chỉ mục mà chỉ bao gồm các văn bản có trường được đánh chỉ
mục. Bất kỳ văn bản nào bị thiếu trường đánh chỉ mục thưa thớt đều không được lưu vào
trong chỉ mục. Các chỉ mục là thưa thớt vì bị thiếu những văn bản không có giá trị của

trường được đánh chỉ mục.
Chỉ mục thưa thớt, theo định nghĩa, là không đầy đủ và hoạt động khác với chỉ mục
đầy đủ. Khi sử dụng chỉ mục thưa thớt để sắp xếp, một vài văn bản trong bộ sưu tập sẽ
không được trả về. Đó là do chỉ những văn bản được đánh chỉ mục mới được trả về.
db.people.ensureIndex({title : 1}, {sparse : true})
db.people.save({name:"Jim"})
db.people.save({name:"Sarah", title:"Princess"})
db.people.find({title:{$ne:null}}).sort({title:1})
// returns only Sarah
3.4.2.4 Chỉ mục duy nhất
MongoDB hỗ trợ đánh chỉ mục duy nhất, đảm bảo rằng không có văn bảo nào được
chèn mà giá trị của khóa được đánh chỉ mục lại trùng với văn bản đã tồn tại. Để tạo ra
một chỉ mục đảm bảo ràng không có 2 văn bản có cùng giá trị cho 2 trường firstname và
lastname ta làm như sau:
db.things.ensureIndex({firstname: 1, lastname: 1}, {unique: true});
Khóa bị thiếu
Khi một văn bản được lưu vào bộ sưu tập với việc đánh chỉ mục duy nhất, bất kỳ
khóa được đánh chỉ mục nào bị thiếu sẽ được chèn vào với giá trị null. Vì vậy, không
được phép chèn nhiều văn bản bị thiếu cùng một khóa được đánh chỉ mục
db.things.ensureIndex({firstname: 1}, {unique: true});
db.things.save({lastname: "Smith"});
// Phép toán này sẽ bị lỗi bởi vì ta đã đánh chỉ mục duy nhất vào trường firstname
db.things.save({lastname: "Jones"});
Giá trị lặp lại
Chỉ mục duy nhất không cho phép một khóa có giá trị nhân bản. Nếu bạn muốn
đánh chỉ mục bằng mọi giá, hãy giữ văn bản đầu tiên trong CSDL và xóa tất cả các
văn bản có giá trị bị nhân bản, thêm tùy chọn dropDups
db.things.ensureIndex({firstname : 1}, {unique : true, dropDups : true})
14
3.4.2.5 Xóa chỉ mục

Xóa tất cả các chỉ mục trên bộ sưu tập:
db.collection.dropIndexes();
Xóa chỉ mục đơn:
db.collection.dropIndex({x: 1, y: -1})
Chạy trực tiếp như một lệnh mà không cần hỗ trợ:
// xóa chỉ mục với khóa là {y:1} trong bộ sưu tập foo:
db.runCommand({dropIndexes:'foo', index : {y:1}})
// xóa tất cả chỉ mục
db.runCommand({dropIndexes:'foo', index : '*'})
3.4.2.6 Đánh chỉ mục lại (reindex)
Lệnh reIndex sẽ xây dựng lại tất cả các chỉ mục cho bộ sưu tập.
db.myCollection.reIndex ()
/ / giống như:
db.runCommand ({reIndex: 'myCollection'})
Thông thường, điều này là không cần thiết. Chúng ta có thể làm điều này nếu kích
thước bộ sưu tập đã thay đổi đáng kể hoặc không gian đĩa được sử dụng bởi các chỉ mục
có vẻ lớn bất thường.
reIndex sẽ bị chậm với các bộ sưu tập lớn.
Các lệnh sửa CSDL tái tạo lại tất cả các chỉ mục trong CSDL.
Lưu ý
- Chỉ mục trong MongoDB phân biệt chữ hoa chữ thường
- Chỉ số thông tin được lưu giữ trong bộ sưu tập system.indexes, chạy
db.system.indexes.find () để xem ví dụ.
Hiệu suất chỉ mục
Việc đánh chỉ mục thực hiện rất nhanh. Cập nhật được thực hiện nhanh hơn vì
MongoDB có thể tìm thấy các văn bản cần cập nhật rất nhanh chóng. Tuy nhiên, với việc
sử dụng chỉ mục, khi ghi dữ liệu vào bộ sưu tập, các khóa sau đó phải được thêm vào
trường chỉ mục. Như vậy, chỉ mục chỉ tốt cho bộ sưu tập có số lượng đọc nhiều hơn rất
nhiều số lượng ghi. Đối với các bộ sưu tập chú trọng ghi, việc sử dụng chỉ mục, trong một
số trường hợp, có thể phản tác dụng. Hầu hết các bộ sưu tập đều chú trọng đọc, vì vậy mà

chỉ mục là tốt trong hầu hết các tình huống.
Sử dụng Sort() mà không cần chỉ mục
15
Chúng ta có thể sử dụng sort() để trả về dữ liệu được sắp thứ tự mà không cần phải dùng
chỉ mục nếu dữ liệu cần trả về là nhỏ (< 4 MB). Đối với những trường hợp này tốt nhất là
sử dụng hàm limit() và sort() cùng nhau.
3.4.3 Sao chép dữ liệu
Có lẽ công việc quan trọng nhất của bất kỳ quản trị viên MongoDB là đảm bảo sao
cho sao chép được thiết lập và hoạt động đúng. Sao chép có thể được sử dụng hoàn toàn
để dự phòng và toàn vẹn dữ liệu hoặc có thể được sử dụng cho mục đích cao hơn như mở
rộng đọc, sao lưu nóng,…
MongoDB hỗ trợ sao chép dữ liệu không đồng bộ giữa các máy chủ. Tại một thời
điểm, chỉ có 1 máy chủ hoạt động để ghi (primary hay master).
Có hai hình thức sao chép.
* Master-Slave Replication
* Replica Sets.
Master-Slave Replication
Sao chép Master-slave là mô hình sao chép phổ biến nhất được hỗ trợ bởi
MongoDB. Mô hình này rất linh hoạt và có thể được sử dụng để sao lưu, dự phòng, mở
rộng đọc, …
Hình 5.2 minh họa mô hình Master – Slave bao gồm 2 nút, một nút làm Master, nút còn
lại làm Slave
Hình 5.2. Mô hình Master – Slave hai nút
Hình 5.3 minh họa mô hình Master – Slave bao gồm 4 nút, một nút làm Master, 3
nút còn lại làm Slave
16
Hình 5.3. Mô hình Master – Slave bốn nút
Để thiết lập cần khởi động nút master và một hoặc nhiều nút slave, các nút này đều
biết địa chỉ của nút master. Để khởi động master, chạy mongod master. Để khởi động
slave, chạy mongod slave source master_address, trong đó master_address là địa chỉ

của nút master vừa được khởi động
Replica Sets
Replica Sets là một cụm master-slave tự động chịu lỗi. Replica Sets không có một
master cố định: một master được bầu chọn và có thể thay đổi đến nút khác nếu master bị
lỗi.
Hình 5.4 mô phỏng mô hình Replica Sets gồm 2 nút.
Hình 5.4. Mô hình Replica Sets hai nút
Khi server chính chết, server cấp 2 chở thành server chính (hình 5.5).
Hình 5.5. Replica Sets – Bầu chọn master mới
17
Nếu server chính ban đầu hoạt động trở lại, nó trở thành server cấp 2 (hình 5.6).
Hình 5.6. Server chính trở thành server cấp 2
3.4.4 Truy vấn
Một trong những tính năng tốt nhất của MongoDB là hỗ trợ truy vấn động (ad hoc).
Hệ thống hỗ trợ truy vấn động không yêu cầu bất cứ chỉ mục nào để tìm dữ liệu. Người
dùng có thể tìm dữ liệu với việc sử dụng bất kỳ tiêu chuẩn nào. Với CSDL quan hệ, truy
vấn động là chuẩn hóa.
Đối tượng biểu thức truy vấn
MongoDB hỗ trợ một số các đối tượng truy vấn để lấy dữ liệu. Ví dụ, giả sử chúng ta
muốn sử dụng trình MongoDB để trả về mọi văn bản trong bộ sưu tập users. Truy vấn sẽ
được viết như sau:
db.users.find({})
Trong trường hợp này, lựa chọn (điều kiện) của chúng ta là trống, nó phù hợp với
mọi văn bản trong bộ sưu tập. Chúng ta xem thêm một số ví dụ:
db.users.find({'last_name': 'Smith'})
Ở đây, lựa chọn của chúng ta là tất cả các văn bản mà thuộc tính last_name là Smith.
Các tùy chọn truy vấn
Lựa chọn các trường
Ngoài các biểu thức truy vấn, truy vấn MongoDB còn có thể thêm vào các tham số.
Ví dụ, chúng ta muốn các số CMT của tất cả người có họ là Smith, ta có thực hiện truy

vấn:
// lấy trường ssn của các văn bản có last_name == 'Smith':
db.users.find({last_name: 'Smith'}, {'ssn': 1});
// lấy tất cả các trường ngoại trừ trường thumbnail đối với tất cả các văn bản.
db.users.find({}, {thumbnail:0});
Chú ý rằng, trường _id luôn luôn được trả về ngay cả khi không yêu cầu
Sắp xếp
18
Truy vấn MongoDB có thể trả về kết quả được sắp xếp. Để trả về tất cả các văn bản
mà trường last_name được sắp xếp theo thứ tự tăng dần, ta viết truy vấn sau:
db.users.find({}).sort({last_name: 1});
Bỏ qua và giới hạn
MongoDB luôn luôn hỗ trợ bỏ qua và giới hạn để phân trang một cách dễ dàng. Ví
dụ ta muốn bỏ qua 20 họ đầu tiên và giới hạn kết quả đến 10, ta viết truy vấn sau:
db.users.find().skip(20).limit(10);
db.users.find({}, {}, 10, 20); // giống như lệnh trên nhưng không rõ ràng.
slaveOk
Khi thực hiện truy vấn ở một hoặc nhiều bản sao, trình tiện ích gửi yêu cầu đến
master, để thực hiện truy vấn đối với slave, truy vấn có thể chạy với tùy chọn slaveOk.
db.getMongo().setSlaveOk(); // cho phép truy vân slave
db.users.find( )
Con trỏ
Các truy vấn CSDL được thực hiện với phương thức find(), với kỹ thuật này một con
trỏ được trả về. Con trỏ sau đó được sử dụng lặp đi lặp lại để lấy tất cả các văn bản mà
truy vấn trả về. Chúng ta có thể xem ví dụ sau:
> var cur = db.example.find();
> cur.forEach( function(x) { print(tojson(x))});
{"n" : 1 , "_id" : "497ce96f395f2f052a494fd4"}
{"n" : 2 , "_id" : "497ce971395f2f052a494fd5"}
{"n" : 3 , "_id" : "497ce973395f2f052a494fd6"}

3.4.5 GridFS
GridFS cung cấp cơ chế để lưu các dữ liệu có kích cỡ lớn. GridFS hoạt động:
- Chia 1 đối tượng lớn thành các mảnh nhỏ (mặc định là cách mảnh này có có độ lớn là
256Kb) - mỗi mảnh này gọi là một chunk
- Mỗi chunk lưu trong một document riêng ở trong chunks collection
- Thông tin về file thì được lưu ở files collection.
- Mỗi dữ liệu chỉ có một file và có thể có một hay nhiều chunk.
Files: File phải chứa các thông tin về _id, độ dài của dữ liệu, cỡ của một chunk,
ngày dữ liệu được lưu, MD5
{
"_id" : <unspecified>, // unique ID for this file
"length" : data_number, // size of the file in bytes
19
"chunkSize" : data_number, // size of each of the chunks. Default is 256k
"uploadDate" : data_date, // date when object first stored
"md5" : data_string // result of running the "filemd5" command on this
file's chunks
}
Ngoài ra thì file có thể có thêm các thông tin về tên file, kiểu nội dung file, alias của file
và các ghi chú thêm:
{
"filename" : data_string, // human name for the file
"contentType" : data_string, // valid mime type for the object
"aliases" : data_array of data_string, // optional array of alias strings
"metadata" : data_object, // anything the user wants to store
}
Chunks:
{
"_id" : <unspecified>, // object id of the chunk in the _chunks collection
"files_id" : <unspecified>, // _id of the corresponding files collection entry

"n" : chunk_number, // chunks are numbered in order, starting with 0
"data" : data_binary, // the chunk's payload as a BSON binary type
}
GridFS được dùng khi:
- Khi có nhiều file cần quản lý.
- Khi có nhiều file do người sử dụng tải lên.
- Khi file thường xuyên bị thay đổi. Với file bị thay đổi nhiều, ta lưu chúng bằng
GridFS, khi ta thay đổi ở một chỗ, thì ở tất cả các client đều nhận được bản cập nhật
của file vừa sửa.
GridFS không được dùng khi:
- Chỉ có ít dữ liệu tĩnh như là một vài file dữ liệu js, css, hình ảnh của một website thì
việc lưu trữ bằng GridFS là không cần thiết.
- Nếu ta cần thiết lập cho dữ liệu được cập nhật một cách tự động và đối tượng được lưu
có kích cỡ nhỏ thì ta có thể lưu bằng tay hoặc cũng có thể lưu dữ liệu dưới dạng
BSON nhị phân.
20
Như vậy, MongoDB là một CSDL hướng văn bản, lưu trữ dữ liệu dưới cặp khóa/giá
trị. Các đối tượng trong MongoDB thường được nhúng trong các đối tượng mức cao hơn
để tăng tốc độ xử lý truy vấn. Để tăng tốc độ truy vấn, người ta cũng thường đánh chỉ
mục cho những bộ sưu tập có tỉ lệ đọc:ghi cao. MongoDB thực hiện truy vấn để lấy dữ
liệu thông qua các biểu thức truy vấn cùng các tham số cần thiết. Với những dự án mà tỉ
lệ lượng dữ liệu ghi vào CSDL lớn hơn lượng đọc thì lựa chọn MongoDB sẽ mang lại
hiệu quả cao.
4 KẾT LUẬN
Sự phát triển không ngừng của công nghệ thông tin, nhu cầu xã hội đòi hòi những hệ
thống phần mềm có khả năng lưu trữ và có tốc độ xử lý cao với một lượng dữ liệu lớn.
Một trong những công nghệ mới ra đời để giải quyết bài toán đó là NoSQL. Một hệ thống
CSDL với nhiều ưu điểm như mã nguồn mở, có khả năng lưu trữ và xử lý một lượng dữ
liệu lớn. Mỗi CSDL trong NoSQL có những đặc điểm chung, đồng thời mang những đặc
trưng riêng, mềm dẻo, phù hợp với những dự án khác nhau.

Trong tài liệu đã đề cập đến MongoDB là một CSDL hướng văn bản, lưu trữ dữ liệu
dưới cặp khóa/giá trị. Để tăng tốc độ xử lý truy vấn, người ta thường sử dụng việc đánh
chỉ mục và nhúng các đối tượng trong MongoDB. MongoDB tỏ ra đặc biệt hiệu quả với
những dự án mà tỉ lệ lượng dữ liệu ghi vào CSDL lớn hơn lượng đọc.
Với các nội dung đã trình bày, tài liệu đã đáp ứng được mục đích, yêu cầu đặt ra.
Tuy nhiên, do hạn chế về thời gian nên mức độ chuyên sâu nghiên cứu của tài liệu chưa
cao. Tài liệu đã đề cập đến một lĩnh vực rất mới mẻ và có tính ứng dụng cao. Hy vọng
vấn đề này sẽ được đông đảo bạn đọc và những người nghiên cứu khoa học quan tâm,
nghiên cứu sâu hơn, khai thác triệt để những ứng dụng to lớn của các hệ cơ sở dữ liệu
hiện đại để tạo ra các phần mềm chất lượng cao, đáp ứng nhu cầu xã hội.
21
5 PHỤ LỤC A. HƯỚNG DẪN CÀI ĐẶT
Bước 1: Tải phiên bản MongoDB mới nhất phù hợp với phiên bản hệ điều hành đang
dùng tại trang: (Mình sử dụng bản Windows 32-bit)
Bước 2: Giải nén file tải về vào thư mục chứa hệ điều hành. Ví dụ, mình giải nén vào ổ
C:\Program files\ và được thư mục: C:\Program Files\mongodb-win32-i386-2.0.3
Bước 3: Tạo 1 thư mục để chứ các csdl của MongoDB.
- Ở đây mình sẽ tạo tiếp ở ổ C:\ProgramData, thư mục “mongoDB”
- Tạo thêm thư mục con ở bên trong có tên là "data" và “db” bên trong “data”
Và đây sẽ là nơi chứa các csdl. (c:\ProgramData\mongodb\data\db)
Bước 4: Tạo file chạy cho MongoDB
- Mở 1 editor bất kỳ như "notepad" của win. và copy nội dung sau:
C:\Program Files\mongodb-win32-x86_64-2.0.3\bin\mongod.exe
dbpath=C:/ProgramData/mongodb/data/db
PAUSE
(tên thư mục đường dẫn có thể thay đổi tùy theo phiên bản)
- Và lưu dưới dạng đuôi mở rộng là .bat
Bước 5: Sau khi xong thì bạn chạy file .bat mà bạn vừa tạo đó lên. Nếu xuất hiện màn
hình Console như hình dưới đây là đã cài đặt thành công.
** Chú ý là các không được tắt file này đi.

Để kiểm tra ta mở 1 cửa sổ Console khác để thực hiện tạo một csdl test.
22
Ta chỉ đến thư mục theo máy và thực hiện như hình dưới đây:
23
6 PHỤ LỤC B. MỘT SỐ CÚ PHÁP CÂU LỆNH
CREATE TABLE USERS (a
Number, b Number)
db.createCollection("mycoll")
ALTER TABLE users ADD không có
INSERT INTO USERS
VALUES(3,5)
db.users.insert({a:3,b:5})
SELECT a,b FROM users db.users.find({}, {a:1,b:1})
SELECT * FROM users db.users.find()
SELECT * FROM users WHERE
age=33
db.users.find({age:33})
SELECT a,b FROM users WHERE
age=33
db.users.find({age:33}, {a:1,b:1})
SELECT * FROM users WHERE
age=33 ORDER BY name
db.users.find({age:33}).sort({name:1})
SELECT * FROM users WHERE
age>33
db.users.find({age:{$gt:33}})
SELECT * FROM users WHERE
age!=33
db.users.find({age:{$ne:33}})
SELECT * FROM users WHERE

name LIKE "%Joe%"
db.users.find({name:/Joe/})
SELECT * FROM users WHERE
name LIKE "Joe%"
db.users.find({name:/^Joe/})
SELECT * FROM users WHERE
age>33 AND age<=40
db.users.find({'age':{$gt:33,$lte:40}})
SELECT * FROM users ORDER
BY name DESC
db.users.find().sort({name:-1})
24
SELECT * FROM users WHERE
a=1 and b='q'
db.users.find({a:1,b:'q'})
SELECT * FROM users LIMIT 10
SKIP 20
db.users.find().limit(10).skip(20)
SELECT * FROM users WHERE
a=1 or b=2
db.users.find( { $or : [ { a : 1 } , { b : 2 } ] } )
SELECT * FROM users LIMIT 1 db.users.findOne()
SELECT order_id FROM orders o,
order_line_items li WHERE
li.order_id=o.order_id AND
li.sku=12345
db.orders.find({"items.sku":12345},{_id:1})
SELECT customer.name FROM
customers,orders WHERE
orders.id="q179" AND

orders.custid=customer.id
var o = db.orders.findOne({_id:"q179"});
var name = db.customers.findOne({_id:o.custid})
SELECT DISTINCT last_name
FROM users
db.users.distinct('last_name')
SELECT COUNT(*y)FROM users db.users.count()
SELECT COUNT(*y)
FROM users where AGE > 30
db.users.find({age: {'$gt': 30}}).count()
SELECT COUNT(AGE) from users db.users.find({age: {'$exists': true}}).count()
CREATE INDEX myindexname ON
users(name)
db.users.ensureIndex({name:1})
CREATE INDEX myindexname ON
users(name,ts DESC)
db.users.ensureIndex({name:1,ts:-1})
UPDATE users SET a=1 WHERE
b='q'
db.users.update({b:'q'}, {$set:{a:1}}, false, true)
25

×