Quay lại

Cách Sử Dụng MongoDB (NoSQL) Trong Laravel Chuyên mục PHP và Laravel    2024-05-26    37 Lượt xem    34 Lượt thích    comment-3 Created with Sketch Beta. 0 Bình luận

Cách Sử Dụng MongoDB (NoSQL) Trong Laravel

Như các bạn biết thì MongoDB là một loại None-Relational-Database, nó có rất nhiều lợi ích so với cơ sở dữ liệu truyền thống SQL như là hiệu suất cao, linh hoạt và mở rộng dễ dàng, hỗ trợ đa nền tảng và ngôn ngữ lập trình, vv. Bạn nào chưa biết về Mongodb thì có thể xem qua bài Học MongoDB cơ bản và nâng cao để biết thêm một số khái niệm trong MongoDB nhé! Dưới đây là một số khái niệm so sánh giữa RDBMS terminology với MongoDB:

RDBMS MongoDB
Database Database
Table Collection
Tuple/Row Document
column Field
Table Join Embedded Documents
Primary Key Primary Key (Giá trị mặc định là _id được cung cấp bởi chính MongoDB)
Database Server và Client
Mysqld/Oracle mongod
mysql/sqlplus mongo

Hôm nay chúng ta sẽ cùng nhau tích hợp MongoDB vào Laravel để tạo một REST back end đơn giản cho một ứng dụng front-end và cùng tìm hiểu các khía cạnh của MongoDB. Việc sử dụng MongoDB không ảnh hưởng đến phần front-end web của Laravel, vì vậy chúng ta sẽ sử dụng tính năng API routing tích hợp sẵn của Laravel trong bài viết này. Với bài này chúng ta sẽ sử dụng MongoDB Cloud (MongoDB Atlas) thay vì chúng ta tự cấu hình và cài đặt một MongoDB server trên một máy chủ như  AWS, Google Cloud Platform (GCP), Microsoft Azure, các bạn cũng có thể dùng máy host (máy tính của các bạn đang sử dụng) để cài MonggoDB server luôn cũng được. Dưới đây mình sẽ đưa ra sự so sánh cho các bạn dễ hình dung và lý do tại sao nhé!

  • Tự cài đặt một MongoDB server: Bạn có toàn quyền kiểm soát máy chủ và cài đặt MongoDB theo ý muốn. Tuy nhiên, bạn cần tự quản lý bảo mật, sao lưu và duy trì hệ thống.
  • Sử dụng MongoDB Atlas: Dịch vụ đám mây cung cấp nhiều tiện ích như tự động sao lưu, bảo mật, và khả năng mở rộng dễ dàng. Tuy nhiên, chi phí có thể cao hơn và bạn cần tuân theo các hạn chế của dịch vụ.

Yêu Cầu

Để các bạn dễ cài đặt và tích hợp MongoDB Và Laravel thì, MongoDB cũng đã hỗ trợ các bạn doc để cài đặt "Tích hợp MongoDB và Laravel" nó chỉ cho bạn cách cấu hình môi trường phát triển Laravel-MongoDB.

Cài Đặt Laravel

Chúng ta hãy tạo một dự án Laravel bằng cách tạo một thư mục dự án Laravel. Từ bên trong thư mục mới đó, tạo một dự án Laravel gọi là laravel-app bằng cách chạy lệnh sau, lệnh này sử dụng Laravel:

composer create-project laravel/laravel laravel-app

Sau đó chúng ta sẽ sử dụng lệnh sau để running dự án Laravel:

cd laravel-app
php artisan serve

MongoDB connection

Kiểm tra xem driver MongoPHP đã được cài đặt và chạy hay chưa?

Để kiểm tra driver MongoDB đã hoạt động trên máy chủ web của chúng ta hay chưa, chúng ta có thể thêm routing trong /routes/web.php và thêm một route như sau:

Route::get('/info', function () {
    phpinfo();
});​

Sau đó truy cập trang web tại địa chỉ http://127.0.0.1:8000/info  và chúng ta sẽ thấy trang PHPinfo. Tìm phần MongoDB trên trang, chúng ta sẽ thấy một cái gì đó giống như hình dưới đây. Điều này có nghĩa là driver MongoDB PHP đã được tải và sẵn sàng. 

Để tích hợp MongoDB với Laravel, chúng ta sẽ sử dụng packages mongodb/laravel-mongodb package này mở rộng chức năng của Eloquent ORM của Laravel để làm việc mượt mà với MongoDB.

Bạn có thể cài đặt package này bằng cách chạy lệnh sau trong thư mục dự án Laravel của bạn:

composer require mongodb/laravel-mongodb:4.0.0

Tiếp theo, cập nhật cấu hình cơ sở dữ liệu để thêm chuỗi kết nối và thông tin xác thực của MongoDB. Mở tệp /config/database.php và cập nhật mảng 'connections' như sau:

'connections' => [
        'mongodb' => [
            'driver' => 'mongodb',
            'dsn' => env('MONGODB_URI'),
            'database' => env('MONGODB_DATABASE'),
        ],
'default' => env('DB_CONNECTION', 'mongodb')

Trong file .env các bạn thêm:

MONGODB_URI=mongodb+srv://USERNAME:PASSWORD@clustername.subdomain.mongodb.net/?retryWr
MONGODB_DATABASE=your_data_base

Ứng dụng Laravel của chúng ta bây giờ có thể kết nối với cơ sở dữ liệu MongoDB. Hãy tạo một endpoint API để ping xem connect được chưa. Trong /routes/api.php, thêm đoạn code mà mình đã chuẩn bị dưới đây, lưu lại và truy cập vào địa chỉ localhost/api/ping/.

API sẽ trả về đối tượng {"msg": "MongoDB is accessible!"}. Nếu có thông báo lỗi, có thể là do vấn đề cấu hình. 

Route::get('/ping', function (Request  $request) {    
    $connection = DB::connection('mongodb');
    $msg = 'MongoDB is accessible!';
    try {  
        $connection->command(['ping' => 1]);  
    } catch (\Exception  $e) {  
        $msg = 'MongoDB is not accessible. Error: ' . $e->getMessage();
    }
    return ['msg' => $msg];
});

Nếu như các bạn gặp lỗi:

Error Message: MongoError: bad auth Authentication failed through URI string

Hãy sử dụng password mà Mongodb genarated cho cho các bạn thay vì tự mình định nghĩa mình đã bị lỗi này và mình đã làm theo các bước dưới đây:

  • Step 1:- Click Database Access From left Side Navigation of MongoDB Atlas page.
  • Step 2:- Select your username and and click on the edit button from right side.
  • Step 3:- Click to change password.
  • Step 4:- Click update user.

Migrations

Mặc dù bạn KHÔNG cần Migrations khi sử dụng MongoDB, bạn vẫn có thể sử dụng chúng, ví dụ, để thêm một chỉ mục. Để sử dụng Migrations, bạn phải sử dụng Class Blueprint từ MongoDB thay vì Illuminate.

use Illuminate\Database\Migrations\Migration;
#use Illuminate\Support\Facades\Schema;
use MongoDB\Laravel\Schema\Blueprint;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $collection) {
            $collection->index('title');
        });
    }
};​

Migration này sẽ tạo một collection có tên là posts và thêm một chỉ mục. Một collection trong MongoDB tương đương với một bảng trong MySQL.

Để biết thêm thông tin về Schema Builder, hãy kiểm tra document chính thức.

Trước khi tìm hiểu về MongoDB Eloquent mình sẽ đưa ra cách mà chúng ta hay làm với dạng cơ sở dữ liệu mysql trước để chúng ta đưa ra điểm khác biệt giữa chúng.

Classic Eloquent model

Đầu tiên, chúng ta tạo một model Classic bằng cách chạy lệnh:

php artisan make:model CustomerSQL --migration​

Sau khi thực thi, nó sẽ tạo ra cho ra hai file, CustomerSQL.phpYY_MM_DD_xxxxxx_create_customer_s_q_l_s_table.php. Sau đó thì chúng ta thêm cấu hình migration trong phương thức up() như sau:

public function up()
{
     Schema::connection('mysql')->create('customer_sql', function (Blueprint  $table) {
      $table->id();
      $table->uuid('guid')->unique();
      $table->string('first_name');
      $table->string('family_name');
      $table->string('email');
      $table->text('address');
      $table->timestamps();
      });
}

Sau đó thì chúng ta chạy lệnh:

php artisan migrate --path=/database/migrations/YY_MM_DD_xxxxxx_create_customer_s_q_l_s_table.php

Khi vào trong phpmyadmin chúng ta sẽ có thông tin sau:

Tiếp theo, chúng ta có thể sửa đổi model trong tệp CustomerSQL.php để phù hợp với schema của chúng ta.

// This is the standard Eloquent Model
use Illuminate\Database\Eloquent\Model;
class  CustomerSQL  extends  Model
{
    use  HasFactory;
    // the selected database as defined in /config/database.php
    protected  $connection = 'mysql';
    // the table as defined in the migration
    protected  $table= 'customer_sql';
    // our selected primary key for this model
    protected  $primaryKey = 'guid';
    //the attributes' names that match the migration's schema
    protected  $fillable = ['guid', 'first_name', 'family_name', 'email', 'address'];
}

Bây giờ chúng ta sẽ sang sử dụng MongoDB xem nó có gì khác biệt nhé!

MongoDB Eloquent model

Hãy tạo một model Eloquent cho cơ sở dữ liệu MongoDB của chúng ta tên là "CustomerMongoDB" bằng cách chạy lệnh sau từ thư mục của dự án:

php artisan make:model CustomerMongoDB​

Laravel sẽ tạo ra một Class CustomerMongoDB trong tệp models/CustomerMongoDB.php như được hiển thị dưới đây. Theo mặc định, các model sử dụng kết nối cơ sở dữ liệu 'default', nhưng chúng ta có thể chỉ định kết nối nào sẽ sử dụng bằng cách thêm thành viên $connection vào Class. Tương tự, có thể chỉ định tên colection thông qua một property $collection.

Chú ý: Cách Class model cơ sở được thay thế trong câu lệnh 'use'. Điều này là cần thiết để đặt "_id" làm khóa chính và tận dụng các tính năng nâng cao của MongoDB.

//use Illuminate\Database\Eloquent\Model;
 use MongoDB\Laravel\Eloquent\Model;

class  CustomerMongoDB  extends  Model
{
    use  HasFactory;

    // the selected database as defined in /config/database.php
    protected  $connection = 'mongodb';

    // equivalent to $table for MySQL
    protected  $collection = 'customers';

    // defines the schema for top-level properties (optional).
    protected  $fillable = ['guid', 'first_name', 'family_name', 'email', 'address'];
}

Định nghĩa extended class  gần như giống hệt với Class mặc định của Laravel. Lưu ý rằng $table được thay thế bởi $collection để sử dụng tên gọi của MongoDB.

Chúng ta vẫn có thể sử dụng Eloquent Migrations với MongoDB (sẽ nói thêm về điều này ở phần dưới), nhưng việc định nghĩa schema và tạo một collection bằng Laravel-MongoDB Migration là tùy chọn vì schema linh hoạt của MongoDB đã tự động thêm các schema như là varchar, int, ... cho chúng ta, việc của chúng ta bây giờ là chỉ cần thêm bản ghi cho table mà thôi.

Nếu chúng ta muốn áp dụng một schema, chúng ta hoàn toàn có thể! MongoDB có một cơ chế xác thực schema tuyệt vời bằng cách cung cấp một document xác thực khi tạo collection thủ công bằng cách sử dụng db.createcollection(). Chúng ta sẽ đề cập đến điều này trong một bài viết sắp tới.

CRUD Eloquent

Khi các model đã sẵn sàng, việc tạo dữ liệu cho một backend MongoDB không có gì khác biệt, và đó là điều mà chúng ta mong đợi từ một ORM.

Dưới đây, chúng ta có thể so sánh các endpoint API /api/create_eloquent_mongo/ và /api/create_eloquent_sql/. Mã nguồn là giống hệt nhau, ngoại trừ các tên model khác nhau là CustomerMongoDBCustomerSQL.

Route::get('/create_eloquent_sql', function (Request  $request) {
    $success = CustomerSQL::create([
        'guid'=> 'cust_0000',
        'first_name'=> 'John',
        'family_name' => 'Doe',
        'email' => 'j.doe@gmail.com',
        'address' => '123 my street, my city, zip, state, country'
    ]);

    ...
});

Route::get('/create_eloquent_mongo', function (Request  $request) {
    $success = CustomerMongoDB::create([
        'guid'=> 'cust_1111',
        'first_name'=> 'John',
        'family_name' => 'Doe',
        'email' => 'j.doe@gmail.com',          
        'address' => '123 my street, my city, zip, state, country'
    ]);

    ...
});

Sau khi thêm document, chúng ta có thể truy xuất nó bằng cách sử dụng hàm "where" của Eloquent như sau:

Route::get('/find_eloquent/', function (Request  $request) {
    $customer = CustomerMongoDB::where('guid', 'cust_1111')->get();
    ...
});

Eloquent cho phép chúng ta tìm kiếm dữ liệu bằng cách sử dụng các truy vấn phức tạp với nhiều điều kiện match. Các bạn có thể tham khảo thêm các câu lệnh truy vấn ở đây Laravel MongoDB query tests. Nó là một nơi để tìm thêm ví dụ về cú pháp và sẽ được cập nhật liên tục.

Tất nhiên, chúng ta cũng có thể Cập nhật và Xóa các bản ghi bằng Eloquent như được hiển thị trong mã dưới đây:

Route::get('/update_eloquent/', function (Request  $request) {
 $result = CustomerMongoDB::where('guid', 'cust_1111')->update( ['first_name' => 'Jimmy'] );
    ...
});

Route::get('/delete_eloquent/', function (Request  $request) {
    $result = CustomerMongoDB::where('guid', 'cust_1111')->delete();
    ...
});

Eloquent là một cách dễ dàng để bắt đầu với MongoDB, và mọi thứ hoạt động rất giống như chúng ta mong đợi. Ngay cả với một schema đơn giản, chúng ta có thể thấy lợi ích từ scalability, high data reliability, and cluster availability của clusters và sharding được quản lý hoàn toàn của MongoDB Atlas.

Tại thời điểm này, service back-end kết nối với MongoDB của chúng ta đã sẵn sàng và hoạt động, và đây có thể là kết thúc của một bài viết "CRUD" điển hình. Tuy nhiên, MongoDB có thể làm được nhiều hơn thế, vì vậy các bạn hãy tiếp tục đọc nhé.

CRUD With Nested Data

Dữ liệu lồng nhau (nested data) trong MongoDB là một cấu trúc dữ liệu cho phép bạn lưu trữ các document bên trong các document khác. Điều này có nghĩa là một document có thể chứa các trường có giá trị là các document khác, mảng hoặc các cấu trúc dữ liệu phức tạp khác. Dữ liệu lồng nhau giúp lưu trữ các mối quan hệ và cấu trúc dữ liệu phức tạp một cách tự nhiên và dễ dàng trong MongoDB mà không cần phải sử dụng các bảng liên kết như trong cơ sở dữ liệu quan hệ.

Trong ví dụ dưới đây, trường 'address' đã chuyển từ kiểu string sang kiểu đối tượng(object). Trường 'email' đã chuyển từ kiểu string sang kiểu mảng (các chuỗi). Mảng và đối tượng không phải là các kiểu được hỗ trợ trong MySQL.

Route::get('/create_nested', function () {
    $message = "executed";
    $success = null;

    $address = new  stdClass;
    $address->street = '123 my street name';
    $address->city = 'my city';
    $address->zip= '12345';
    $emails = ['s2sontech@gmail.com', 's2sontech@work.com'];

    try {
        $customer = new  CustomerMongoDB();
        $customer->guid = 'cust_666';
        $customer->first_name = 'son';
        $customer->family_name= 'tech';
        $customer->email= $emails;
        $customer->address= $address;
        $customer->test = $address;
        $customer->save(); // save() returns 1 or 0
        $success = $customer;
    }
    catch (\Exception  $e) {
        $message = $e->getMessage();
    }
    return ['msg' => $message, 'data' => $success];
});

Nếu chúng ta chạy endpoint API localhost/api/create_nested/, nó sẽ tạo một document như đại diện JSON dưới đây. Các trường datetime updated_atcreated_at được tự động thêm vào bởi Eloquent, và có thể tắt tính năng này của Eloquent.

{
  "msg": "executed",
  "data": {
    "guid": "cust_666",
    "first_name": "son",
    "family_name": "tech",
    "email": [
      "s2sontech@gmail.com",
      "s2sontech@work.com"
    ],
    "address": {
      "street": "123 my street name",
      "city": "my city",
      "zip": "12345"
    },
    "test": {
      "street": "123 my street name",
      "city": "my city",
      "zip": "12345"
    },
    "updated_at": "2024-05-26T13:43:04.774000Z",
    "created_at": "2024-05-26T13:43:04.774000Z",
    "_id": {
      
    }
  }
}

Relationships

Sau khi bạn khởi tạo Class Model như bên dưới thì MongoDB sẽ TỰ ĐỘNG tạo cho các bạn table mà không cần dùng tới migration.

One to One Example

Ví dụ lớp sau đây cho thấy cách định nghĩa mối quan hệ một-một HasOne giữa model PlanetOrbit bằng cách sử dụng phương thức hasOne():

<?php

declare(strict_types=1);

namespace App\Models;

use MongoDB\Laravel\Eloquent\Model;
use MongoDB\Laravel\Relations\HasOne;

class Planet extends Model
{
    protected $connection = 'mongodb';

    public function orbit(): HasOne
    {
        return $this->hasOne(Orbit::class);
    }
}
Ví dụ lớp sau đây cho thấy cách định nghĩa mối quan hệ nghịch đảo BelongsTo giữa OrbitPlanet bằng cách sử dụng phương thức belongsTo():
 
<?php

declare(strict_types=1);

namespace App\Models;

use MongoDB\Laravel\Eloquent\Model;
use MongoDB\Laravel\Relations\BelongsTo;

class Orbit extends Model
{
    protected $connection = 'mongodb';

    public function planet(): BelongsTo
    {
        return $this->belongsTo(Planet::class);
    }
}

Đoạn code mẫu sau đây cho thấy cách khởi tạo một model cho mỗi lớp và thêm mối quan hệ giữa chúng. 

$planet = new Planet();
$planet->name = 'Earth';
$planet->diameter_km = 12742;
$planet->save();


$orbit = new Orbit();
$orbit->period = 365.26;
$orbit->direction = 'counterclockwise';
$planet->orbit()->save($orbit);

Đoạn code sau đây cho thấy cách truy cập các model liên quan bằng cách sử dụng các thuộc tính động như được định nghĩa trong các lớp ví dụ:

$planet = Planet::first();
$relatedOrbit = $planet->orbit;

$orbit = Orbit::first();
$relatedPlanet = $orbit->planet;

Ví dụ, lấy kết quả bài viết đầu tiên sẽ như sau:

\App\Models\Planet::with('orbit')->first()->toJson()​

 Để biết thêm chi tiết về cách sử dụng hasMany, Many to Many, các bạn hãy xem thêm document chính thức.

Transaction

Trong ví dụ sau, transaction bao gồm các thao tác ghi để chuyển tiền từ một tài khoản, được đại diện bởi model Account, sang nhiều tài khoản khác. Nếu tài khoản người gửi không có đủ tiền, giao dịch sẽ bị hủy và không có model nào được cập nhật:

DB::beginTransaction();

$sender = Account::where('number', 223344)->first();
$receiverA = Account::where('number', 776655)->first();
$receiverB = Account::where('number', 990011)->first();

$amountA = 100;
$amountB = 200;

$sender->balance -= $amountA;
$receiverA->balance += $amountA;

$sender->balance -= $amountB;
$receiverB->balance += $amountB;

if ($sender->balance < 0) {
    // insufficient balance, roll back the transaction
    DB::rollback();
} else {
    DB::commit();
}

MongoDB Query API

MongoDB Query API là một tập hợp các phương thức và chức năng mà MongoDB cung cấp để thực hiện các truy vấn dữ liệu đến cơ sở dữ liệu MongoDB. API này cho phép người dùng tạo ra và thực thi các truy vấn đa dạng để truy xuất, tìm kiếm, cập nhật và xóa dữ liệu từ các collection trong MongoDB. Các truy vấn có thể được thực hiện bằng cách sử dụng các phương thức như find(), findOne(), aggregate(), và các toán tử logic và so sánh khác để lọc và sắp xếp dữ liệu theo yêu cầu cụ thể.

Eloquent Và "raw queries"

Chúng ta có thể thực hiện một native MongoDB query  từ model như sau, và model sẽ trả về một collection Eloquent.

$mongodbquery = ['guid' => 'cust_1111'];
   
// returns a "Illuminate\Database\Eloquent\Collection" Object
$results = CustomerMongoDB::whereRaw( $mongodbquery )->get();

Cũng có thể lấy đối tượng collection native của MongoDB và thực hiện một truy vấn sẽ trả về các đối tượng như các document MongoDB native hoặc cursors:

$mongodbquery = ['guid' => 'cust_1111', ];

$mongodb_native_collection = DB::connection('mongodb')->getCollection('customers');

$document = $mongodb_native_collection->findOne( $mongodbquery );  
$cursor = $mongodb_native_collection->find( $mongodbquery );  

Sử dụng trực tiếp collection MongoDB là cách chắc chắn để truy cập vào tất cả các tính năng của MongoDB. Thông thường, mọi người bắt đầu sử dụng collection.insert(), collection.find(), và collection.update() trước tiên.

Với Laravel, có nhiều cách để truy vấn dữ liệu, và API endpoint/find_native/ dưới đây cho thấy cách sử dụng whereRaw(). Ngoài ra, chúng ta có thể sử dụng các phương thức collection indOne() và find() của MongoDB, lần lượt trả về một document và một cursors.

/*
 Tìm bản ghi bằng một Truy vấn MongoDB native
 1 - với Model->whereRaw()
 2 - với native Collection->findOne()
 3 - với native Collection->find()
*/

Route::get('/find_native', function (Request  $request) {
    // một truy vấn MongoDB đơn giản tìm kiếm một khách hàng dựa trên guid
    $mongodbquery = ['guid' => 'cust_2222'];

    // Tùy chọn #1
    //==========
    // sử dụng hàm whereRaw() của Eloquent. Đây là cách dễ dàng nhất để giữ gần với mô hình Laravel
    // trả về một đối tượng "Illuminate\Database\Eloquent\Collection"

    $results = CustomerMongoDB::whereRaw( $mongodbquery )->get();

    // Tùy chọn #2 & #3
    //===============
    // sử dụng đối tượng Collection của trình điều khiển MongoDB nguyên bản. Với nó, bạn có thể sử dụng MongoDB Query API nguyên bản
    $mdb_collection = DB::connection('mongodb')->getCollection('customers');

    // tìm document đầu tiên phù hợp với truy vấn
    $mdb_bsondoc= $mdb_collection->findOne( $mongodbquery ); // trả về một đối tượng "MongoDB\Model\BSONDocument"

    // nếu chúng ta muốn chuyển đổi document MongoDB thành Mô hình Laravel, sử dụng phương thức newFromBuilder() của Mô hình
    $cust= new  CustomerMongoDB();
    $one_doc = $cust->newFromBuilder((array) $mdb_bsondoc);

    // tìm tất cả các document phù hợp với truy vấn
    // Lưu ý: chúng tôi sử dụng find mà không có bất kỳ đối số nào, vì vậy TẤT CẢ document sẽ được trả về

    $mdb_cursor = $mdb_collection->find( ); // trả về một đối tượng "MongoDB\Driver\Cursor"
    $cust_array = array();
    foreach ($mdb_cursor->toArray() as $bson) {
        $cust_array[] = $cust->newFromBuilder( $bson );
    }

    return ['msg' => 'thực thi', 'whereraw' => $results, 'document' => $one_doc, 'mảng con trỏ' => $cust_array];
});

Cập nhật documents được thực hiện bằng cách cung cấp một danh sách các cập nhật cùng với các tiêu chí phù hợp. Dưới đây là một ví dụ sử dụng updateOne(), nhưng updateMany() hoạt động tương tự. updateOne() trả về một document chứa thông tin về số lượng document phù hợp và số lượng document thực sự được sửa đổi.

/*
 Update a record using a native MongoDB Query
*/
Route::get('/update_native', function (Request  $request) {
    $mdb_collection = DB::connection('mongodb')->getCollection('customers');
    $match = ['guid' => 'cust_2222'];
    $update = ['$set' => ['first_name' => 'Henry', 'address.street' => '777 new street name'] ];
    $result = $mdb_collection->updateOne($match, $update );
    return ['msg' => 'executed', 'matched_docs' => $result->getMatchedCount(), 'modified_docs' => $result->getModifiedCount()];
});
{
  "msg": "executed",
  "matched_docs": 1,
  "modified_docs": 1
}

Xóa document dễ dàng như tìm kiếm chúng. Tương tự, có một tiêu chí phù hợp và API trả về một document cho biết số lượng document đã bị xóa.

Route::get('/delete_native', function (Request  $request) {
    $mdb_collection = DB::connection('mongodb')->getCollection('customers');
    $match = ['guid' => 'cust_2222'];
    $result = $mdb_collection->deleteOne($match );
    return ['msg' => 'executed', 'deleted_docs' => $result->getDeletedCount() ];
});

Aggregation pipeline

Aggregation pipeline là một tính năng mạnh mẽ của MongoDB cho phép bạn xử lý và biến đổi dữ liệu từ các collection thông qua một chuỗi các bước (stages). Mỗi bước trong pipeline thực hiện một thao tác cụ thể trên dữ liệu, và đầu ra của bước này là đầu vào cho bước tiếp theo. Điều này cho phép bạn thực hiện các thao tác phức tạp như lọc, sắp xếp, nhóm, và tính toán trên dữ liệu.

Dưới đây là một số bước (stages) phổ biến trong aggregation pipeline:

  1. $match: Lọc các document để chỉ giữ lại những document phù hợp với điều kiện.
  2. $group: Nhóm các document theo một hoặc nhiều trường và thực hiện các phép tính tổng hợp như đếm, trung bình, tổng, tối đa, tối thiểu.
  3. $project: Chọn hoặc tính toán các trường cụ thể để đưa vào kết quả.
  4. $sort: Sắp xếp các document theo thứ tự tăng dần hoặc giảm dần.
  5. $limit: Giới hạn số lượng document đầu ra.
  6. $skip: Bỏ qua một số lượng document nhất định.
  7. $unwind: Tách một mảng trong document thành nhiều document riêng lẻ.

Giả sử chúng ta có collection "movies" và có document như sau:

{
  "_id": "573a1390f29313caabcd4323",
  "title": "The Shawshank Redemption",
  "year": 1994,
  "imdb": {
    "rating": 9.3,
    "votes": 678790,
    "id": 111161
  },
  "genres": ["Drama", "Crime"]  

Dưới đây là cách sử dụng aggregate trong MongoDB kết hợp với Laravel

Route::get('/aggregate', function (Request $request) {
    // Kết nối đến collection 'movies' trong cơ sở dữ liệu MongoDB 'mongodb_mflix'
    $mdb_collection = DB::connection('mongodb')->getCollection('movies');

    // Giai đoạn 1: Tách mảng 'genres' thành các document riêng biệt
    $stage0 = ['$unwind' => ['path' => '$genres']];
    
    // Giai đoạn 2: Nhóm các document theo 'genres' và tính trung bình của 'imdb.rating' cho từng thể loại
    $stage1 = ['$group' => ['_id' => '$genres', 'averageGenreRating' => ['$avg' => '$imdb.rating']]];
    
    // Giai đoạn 3: Sắp xếp kết quả theo 'averageGenreRating' theo thứ tự giảm dần
    $stage2 = ['$sort' => ['averageGenreRating' => -1]];

    // Chuỗi các bước (stages) trong aggregation pipeline
    $aggregation = [$stage0, $stage1, $stage2];
    
    // Thực hiện aggregation pipeline trên collection 'movies'
    $mdb_cursor = $mdb_collection->aggregate($aggregation);
    
    // Trả về kết quả dưới dạng mảng
    return ['msg' => 'executed', 'data' => $mdb_cursor->toArray()];
});
  1. Kết nối với Collection:

    • Đoạn mã này sử dụng kết nối đến collection 'movies' trong cơ sở dữ liệu 'mongodb' của MongoDB.
  2. Các Giai đoạn trong Aggregation Pipeline:

    • $unwind:

      • ['path' => '$genres'] tách mỗi phần tử trong mảng genres thành một document riêng biệt.
      • Ví dụ: Một document với genres: ["Drama", "Crime"] sẽ được tách thành hai document riêng biệt, một với genres: "Drama" và một với genres: "Crime".
      • Sử dụng path nó sẽ tách ra cho chúng ta như thế này:
      • $stage0 = ['$unwind' => ['path' => '$genres']];​
      • // Tách ra lần 1
        {
          "_id": "573a1390f29313caabcd4323",
          "title": "The Shawshank Redemption",
          "year": 1994,
          "imdb": {
            "rating": 9.3,
            "votes": 678790,
            "id": 111161
          },
          "genres": "Drama"
        }
        
        // Tách ra lần 2
        {
          "_id": "573a1390f29313caabcd4323",
          "title": "The Shawshank Redemption",
          "year": 1994,
          "imdb": {
            "rating": 9.3,
            "votes": 678790,
            "id": 111161
          },
          "genres": "Crime"
        }
    • $group:

      • ['_id' => '$genres', 'averageGenreRating' => ['$avg' => '$imdb.rating']] nhóm các document theo thể loại ($genres) và tính trung bình của trường imdb.rating cho từng thể loại.
      • _id đại diện cho giá trị mà các document sẽ được nhóm theo, trong trường hợp này là thể loại phim.
    • $sort:

      • ['averageGenreRating' => -1] sắp xếp các kết quả theo averageGenreRating theo thứ tự giảm dần.
  3. Thực hiện Aggregation:

    • Aggregation pipeline được thực hiện trên collection 'movies'.
    • Kết quả của aggregation pipeline được trả về dưới dạng mảng và gửi lại như một phần của phản hồi API.
    • [
        { "_id": "Drama", "averageGenreRating": 8.5 },
        { "_id": "Crime", "averageGenreRating": 8.2 },
        { "_id": "Comedy", "averageGenreRating": 7.9 }
      ]
      

 Index

Đánh index bằng cách sử dụng Eloquent's Migrations.

public function up() {
  Schema::connection('mongodb')->create('users', function ($collection) {
  $collection->unique('guid'); // Ensure the guid is unique since it will be used as a primary key.
  });
}

Đánh index bằng cách sử dụng MongoDB's native API.

Route::get('/create_index/', function (Request  $request) {

    $indexKeys = ["guid" => 1];
    $indexOptions = ["unique" => true];
    $result = DB::connection('mongodb')->getCollection('laracoll')->createIndex($indexKeys, $indexOptions);

    return ['msg' => 'executed', 'data' => $result ];
});

Bình luận (0)

Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough

Bài viết liên quan

Learning English Everyday