Table of Contents
1. Mô hình
1.1. Các mô hình trong MongoDb
1.1.1. Mô hình Standalone
Mô hình Standalone trong MongoDB là cấu hình đơn giản nhất, nơi MongoDB chạy trên một máy chủ duy nhất. Đây là mô hình cơ bản nhất và dễ thiết lập nhất, thích hợp cho môi trường phát triển, thử nghiệm hoặc các ứng dụng nhỏ không yêu cầu độ khả dụng cao hoặc khả năng mở rộng.
Đặc điểm của mô hình Standalone:
- Đơn giản và Dễ Thiết Lập: Cài đặt MongoDB trên một máy chủ duy nhất là dễ dàng và nhanh chóng.
- Hiệu Suất: Hiệu suất có thể bị giới hạn bởi tài nguyên của một máy chủ duy nhất, không có tính năng phân đoạn (sharding) hay sao lưu (replication) để cải thiện hiệu suất.
- Không Có Tính Khả Dụng Cao: Nếu máy chủ gặp sự cố, toàn bộ cơ sở dữ liệu sẽ không khả dụng, không có khả năng tự động chuyển đổi dự phòng.
- Không Có Sao Lưu (Replication): Không có bản sao dự phòng của dữ liệu, dữ liệu có nguy cơ bị mất nếu máy chủ gặp sự cố.
- Thích Hợp Cho: Môi trường phát triển và thử nghiệm, ứng dụng nhỏ không yêu cầu độ khả dụng cao.
1.1.2. Mô hình Replicate
Mô hình Replica Set trong MongoDB là một cấu hình nâng cao được sử dụng để cung cấp độ khả dụng cao và sao lưu dữ liệu. Trong mô hình này, dữ liệu được sao chép trên nhiều máy chủ (node) để đảm bảo rằng nếu một node gặp sự cố, các node khác vẫn có thể cung cấp dữ liệu và tiếp tục phục vụ các yêu cầu của người dùng.
Đặc điểm của mô hình Replica Set:
- Khả Dụng Cao (High Availability): Dữ liệu được sao chép trên nhiều node, giúp đảm bảo rằng hệ thống vẫn hoạt động ngay cả khi một node bị lỗi. Nếu node chính (primary) gặp sự cố, một trong các node phụ (secondary) sẽ tự động được bầu chọn làm node chính mới.
- Sao Lưu Dữ Liệu (Data Redundancy): Dữ liệu được sao chép trên nhiều node, giảm nguy cơ mất dữ liệu. Các node phụ có thể được cấu hình để sao lưu và lưu trữ dữ liệu lịch sử.
- Cân Bằng Tải (Load Balancing): Các node phụ có thể xử lý các truy vấn chỉ đọc, giúp giảm tải cho node chính. Cải thiện hiệu suất của hệ thống khi có nhiều yêu cầu đọc.
- Khả Năng Tự Phục Hồi (Self-Healing): Hệ thống tự động phục hồi khi một node bị lỗi và tự động sao chép dữ liệu khi node mới được thêm vào.
1.1.3. Mô hình Sharding
Mô hình Sharding trong MongoDB là một kỹ thuật được sử dụng để mở rộng cơ sở dữ liệu bằng cách phân phối dữ liệu trên nhiều máy chủ. Mục đích chính của Sharding là xử lý khối lượng dữ liệu lớn và cải thiện hiệu suất của cơ sở dữ liệu bằng cách phân chia dữ liệu thành các phân đoạn nhỏ hơn, gọi là “shard”, và phân phối chúng trên các máy chủ khác nhau.
Đặc điểm của mô hình Sharding:
- Mở Rộng Quy Mô (Scalability): Cho phép mở rộng cơ sở dữ liệu một cách tuyến tính bằng cách thêm nhiều máy chủ hơn. Cải thiện khả năng xử lý khối lượng dữ liệu lớn và tăng số lượng truy vấn.
- Phân Phối Dữ Liệu (Data Distribution): Dữ liệu được phân chia thành các shard và phân phối trên nhiều máy chủ. Các shard có thể được lưu trữ trên các cụm máy chủ khác nhau.
- Cân Bằng Tải (Load Balancing): Cân bằng tải giữa các shard giúp cải thiện hiệu suất tổng thể của hệ thống. Các shard có thể được di chuyển hoặc phân phối lại để đảm bảo cân bằng tải.
- Khả Năng Chịu Lỗi (Fault Tolerance): Mỗi shard có thể được cấu hình dưới dạng một replica set để đảm bảo độ khả dụng cao và sao lưu dữ liệu. Nếu một shard gặp sự cố, các replica set khác vẫn có thể tiếp tục phục vụ các yêu cầu của người dùng.
1.2. Kiến trúc MongoDb
1.2.1. Cấu trúc MongoDb
Bảng so sánh mối tương quan với mô hình cơ sở dữ liệu quan hệ:
RDBMS | Database | Table | Column | Row |
---|---|---|---|---|
MongoDb | Database | Collection | Field | Document |
1.2.2. Kiến trúc hoạt động MongoDb
Storage Engine: Trong MongoDb có nhiều Storage Engine khác nha, mỗi loại lại có giải thuật xử lý riêng - có ưu nhược điểm khác nhau. Chịu trách nhiệm lưu trữ và xử lý dữ liệu trên Memory và các file vật lý trên OS.
Các loại Storage Engine:
- MMAPv1
- WiredTiger (mặc định)
- In-Memory (sử dụng với Mongo Enterprise)
2. Cài đặt & sử dụng
2.1. Cài đặt MongoDB PHP Extension
https://www.php.net/manual/en/mongodb.installation.pecl.php
yes '' | sudo pecl install mongodb ... Build process completed successfully Installing '/opt/homebrew/Cellar/php@8.2/8.2.20/pecl/20220829/mongodb.so' install ok: channel://pecl.php.net/mongodb-1.19.3 Extension mongodb enabled in php.ini
2.2. Sử dụng với PHP Laravel
config/database.php config:
<?php return [ 'connections' => [ 'mongodb' => [ 'driver' => 'mongodb', 'host' => env('MONGODB_HOST', 'localhost'), 'port' => env('MONGODB_PORT', 27017), 'database' => env('MONGODB_DATABASE'), 'username' => env('MONGODB_USERNAME'), 'password' => env('MONGODB_PASSWORD'), 'options' => array( 'database' => env('MONGODB_DATABASE') ) ], ],
2.2.1. Sử dụng thư viện mongodb/mongodb
<?php namespace App\Console\Commands; use Illuminate\Console\Command; use MongoDB\Client; class MongoDbTestCommand extends Command { /** * The name and signature of the console command. * https://www.mongodb.com/docs/php-library/current/tutorial/install-php-library/ * @var string */ protected $signature = 'app:mongo-db-test'; /** * The console command description. * * @var string */ protected $description = 'Command description'; /** * Execute the console command. */ public function handle() { $host = config('database.connections.mongodb.host'); $port = config('database.connections.mongodb.port'); $dbName = config('database.connections.mongodb.database'); $conn = new Client("mongodb://{$host}:{$port}"); $db = $conn->listDatabases(); //$db = $conn->$dbName; $db = $conn->selectDatabase($dbName); //$collection = $conn->test->test; $collection = $db->selectCollection('test'); //$this->insertCollections($collection); //$this->updateCollection($collection); //var_dump($this->getCollections($db)); $this->find($collection); //$this->deleteOne($collection); //$this->deleteMany($collection); } /** * findOne * * @param mixed $collection * @return void */ private function findOne($collection){ $result = $collection->findOne(['category' => 'Bar']); var_dump($result->title, $result->content, $result->category); } /** * find * * @param mixed $collection * @return void */ private function find($collection){ $result = $collection->find([ 'category' => 'Bar', 'title' => ['$regex' => 'Foo', '$options'=> 'i'] ], [ 'limit' => 2, 'skip' => 0 ]); //foreach ($result as $row) { // var_dump($row->title, $row->category); //} var_dump($result->toArray()); } /** * deleteOne * * @param mixed $collection * @return void */ private function deleteOne($collection){ $result = $collection->deleteOne(['category' => 'Foo']); var_dump($result->getDeletedCount()); } /** * deleteMany * * @param mixed $collection * @return void */ private function deleteMany($collection){ $result = $collection->deleteMany( [ 'title' => [ '$regex' => 'Foo', '$options' => 'i' ] ]); var_dump($result->getDeletedCount()); } /** * getDatabases * * @param mixed $conn * @return void */ private function getDatabases($conn){ $db = $conn->listDatabases(); foreach ($db as $databaseInfo) { var_dump($databaseInfo->getName()); } } /** * dropDatabase * * @param mixed $conn * @param mixed $database * @return void */ private function dropDatabase($conn, $database){ return $conn->dropDatabase($database); } /** * getCollections * * @param mixed $db * @return void */ private function getCollections($db){ $result = $db->listCollections(); foreach ($result as $item) { var_dump($item->getName()); } } /** * dropCollection * * @param mixed $db * @param mixed $collection * @return void */ private function dropCollection($db, $collection){ $db->dropCollection($collection); } /** * insertCollections * * @param mixed $collection * @return void */ private function insertCollections($collection){ $insertResult = $collection->insertOne([ 'title' => 'Second Post', 'content' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Odio harum necessitatibus eius magnam, doloribus explicabo omnis natus alias, nisi dolorum ea ab. Nobis quo magnam aliquid molestias, ipsum nihil eum.', 'category' => 'Foo', ]); var_dump($insertResult); $insertResult = $collection->insertMany([ [ 'title' => 'Foo Post', 'content' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Odio harum necessitatibus eius magnam, doloribus explicabo omnis natus alias, nisi dolorum ea ab. Nobis quo magnam aliquid molestias, ipsum nihil eum.', 'category' => 'Foo', ], [ 'title' => 'Bar Post', 'content' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Odio harum necessitatibus eius magnam, doloribus explicabo omnis natus alias, nisi dolorum ea ab. Nobis quo magnam aliquid molestias, ipsum nihil eum.', 'category' => 'Bar'], ]); var_dump($insertResult); } /** * updateCollection * * @param mixed $collection * @return void */ private function updateCollection($collection){ $updatedResult = $collection->updateOne( ['_id' => new \MongoDB\BSON\ObjectId('66ad03ca578cc2020505ad62')], ['$set' => [ 'title' => 'News Title', 'content' => 'News Content', 'category' => 'Foo New', ], ] ); var_dump($updatedResult); $updatedResult = $collection->updateMany( ['category' => 'Foo'], ['$set' => [ 'category' => 'Bar', ], ] ); var_dump($updatedResult); } }
2.2.2. Sử dụng thư viện mongodb/laravel-mongodb
Cài đặt thư viện mongodb/laravel-mongodb:
composer require mongodb/laravel-mongodb:^4.7
2.3. Mongo Shell
tungnt@MacBook-Pro-cua-Nguyen-2 2 % /Users/tungnt/Downloads/mongosh-2.2.15-darwin-arm64/bin/mongosh
2.3.1. Kiểm tra storage engine đang sử dụng
test> db.serverStatus().storageEngine { name: 'wiredTiger', supportsCommittedReads: true, oldestRequiredTimestampForCrashRecovery: Timestamp({ t: 0, i: 0 }), supportsPendingDrops: true, dropPendingIdents: Long('0'), supportsSnapshotReadConcern: true, readOnly: false, persistent: true, backupCursorOpen: false }
2.3.2. Một số lệnh cơ bản
test> show databases; admin 132.00 KiB config 108.00 KiB local 88.00 KiB test 244.00 KiB test> use tungnt switched to db tungnt tungnt> db.mycollection.insertOne({name: "TungNT", age: 35, city: "Hanoi"}) { acknowledged: true, insertedId: ObjectId('66b0b08801bb92333841de0f') } tungnt> show collections; mycollection tungnt> db.mycollection.find() [ { _id: ObjectId('66b0b08801bb92333841de0f'), name: 'TungNT', age: 35, city: 'Hanoi' } ] tungnt> db.mycollection.insertMany([{name: "TungNT", age: 35, city: "Hanoi"}, {name: "VienLD", phone: "+84999888777"}]) { acknowledged: true, insertedIds: { '0': ObjectId('66b0b1e801bb92333841de10'), '1': ObjectId('66b0b1e801bb92333841de11') } } tungnt> db.mycollection.getIndexes() [ { v: 2, key: { _id: 1 }, name: '_id_' } ] tungnt> db.runCommand({collstats: "mycollection"}) { ns: 'tungnt.mycollection', size: 191, count: 3, avgObjSize: 63, numOrphanDocs: 0, storageSize: 36864, freeStorageSize: 16384, capped: false, ... tungnt> db.mycollection.createIndex({name: 1}, {name: "IDX_NAME"}) IDX_NAME tungnt> db.mycollection.getIndexes() [ { v: 2, key: { _id: 1 }, name: '_id_' }, { v: 2, key: { name: 1 }, name: 'IDX_NAME' } ] tungnt> db.mycollection.find({name: "TungNT"}).explain("executionStats") { explainVersion: '2', queryPlanner: { namespace: 'tungnt.mycollection', indexFilterSet: false, parsedQuery: { name: { '$eq': 'TungNT' } }, queryHash: '1AD872C6', planCacheKey: 'B92F173A', maxIndexedOrSolutionsReached: false, maxIndexedAndSolutionsReached: false, maxScansToExplodeReached: false,