← Writing

Laravel: MongoDB with Laravel

What is MongoDB? MongoDB 是目前流行的 NoSQL 資料庫,是一個文檔導向(doc)的資料庫,不使用傳統的表格與行的模式,而是使用 JSONlike 的文檔(在 MongoDB 中稱為 BSON)來存儲資料。這使得數據結構可以非常靈活,能夠存儲更復雜的數據類型並輕鬆進行嵌套。...

laravelmongodb

What is MongoDB?

MongoDB 是目前流行的 NoSQL 資料庫,是一個文檔導向(doc)的資料庫,不使用傳統的表格與行的模式,而是使用 JSON-like 的文檔(在 MongoDB 中稱為 BSON)來存儲資料。這使得數據結構可以非常靈活,能夠存儲更復雜的數據類型並輕鬆進行嵌套。MongoDB 廣泛用於需要處理大量數據並且數據頻繁變動的應用場景中。


要如何在 Laravel 專案中使用 MongoDB?

系統:安裝 MongoDB PHP Extension

sudo pecl install mongodb

並確認在 php.ini 裡有:

extension="mongodb.so"

Laravel 專案:安裝 mongodb/laravel-mongodb

composer require mongodb/laravel-mongodb

註:mongodb/laravel-mongodb 之前叫做 jenssegers/mongodb,因為所有權轉移給 MongoDB, Inc. 而更名為 mongodb/laravel-mongodb

config\database.php 設定 MongoDB 的連線
'default' => env('DB_CONNECTION', 'mongodb'),

...

'mongodb' => [
    'driver' => 'mongodb',
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', 27017),
    'database' => env('DB_DATABASE', ''),
],
app.php 設定 providers
'providers' => [

/*
* Laravel Framework Service Providers...
*/

MongoDB\Laravel\MongoDBServiceProvider::class,

],

Laravel MongoDB CRUD example

以建立 Location Model 作為範例

建立一個 Location Model 並指定連接到 MongoDB:
php artisan make:model Location -mc

這指令會生成 App/Models/Location.phpApp/Http/Controllers/LocationController.php 預設上 artisan 指令會用 Illuminate\Database\Eloquent\Model

但要使用 MongoDB 我們需要用 MongoDB Eloquent model, 也就是要將上面的預設修改為 MongoDB\Laravel\Eloquent\Model

建立 migration(optional)
php artisan make:migration create_locations_table

因爲 MongoDB 是一種 NoSQL 資料庫,不像關聯式資料庫 (MySQL) 使用較嚴謹的 migration,但在 MongoDB 使用 migration 可以知道資料的變更狀態,並保證不同開發環境間的一致性。

use MongoDB\Laravel\Eloquent\Model;

class Location extends Model
{
    protected $connection = 'mongodb';
    protected $collection = 'locations';
    protected $fillable = [
        'country_code',
        'party_id',
        'id',
        ...
    ]

    protected $casts = [
        'publish' => 'boolean',
        'charging_when_closed' => 'boolean',
        'last_updated' => 'datetime',
    ];
}
筆記

Locationcoordinates 是一個包含經度和緯度的 array。為了方便處理,當時使用 Laravel 的 $casts 屬性將 coordinates 轉換成 array。

class Location extends Model
{
    protected $casts = [
        'coordinates' => 'array',
    ];
}

但,當開始使用 Laravel 的 API 資源(APIResource)封裝這些地理位置數據為 JSON 格式進行回應時,就遇到了困難。 雖然 coordinates 在 Model 內部正確地被處理為一個 PHP array,但當通過 APIResource 轉換為 JSON 時,這個 array 並沒有按照預期的方式顯示,因為 APIResource 基本上是將 Model 的數據直接轉換成 JSON,沒有對原始的數據類型做特別處理。

為了解決這個問題,而不是在 APIResource 中再次轉換為 JSON 字串,就是在 APIResource 中直接使用它的原生屬性,而不進行額外的處理。

use Illuminate\Http\Resources\Json\JsonResource;

class LocationResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'coordinates' => $this->coordinates, // 直接使用,無需額外轉換
        ];
    }
}

通過這種方式,確保了當 coordinates 被 APIResource 處理時,它保持為原生的格式,並且在最終的 JSON 回應中正確顯示。

CRUD

  • Create
$location = new Location();
$location->name = '台北 101';
$location->address = '台北市信義區信義路五段7號';
$location->save();

or

$location = Location::create([
    'name' => '台北 101',
    'address' => '台北市信義區信義路五段7號',
]);
  • Read
$locations = Location::all(); // 獲取所有地點
$location = Location::find($id);

若 Model 內有 data 爲 id 和 MongoDB 的 _id 可能會衝突,推薦使用 where 方法來進行精確查詢:

$locations = Location::all(); // 獲取所有地點
$location = Location::where('id', $location_id)->first(); // 根據自定義 ID 查詢
  • Update

使用 where 方法找到特定 ID 的地點並更新:

$location = Location::where('id', $location_id)->first();
$location->name = '台北 101 大樓';
$location->save();

or

$location = Location::where('id', $location_id)->first();
$location->name = '台北 101 大樓';
$location->update();
  • Delete 找到並刪除特定 ID 的地點:
$location = Location::where('id', $location_id)->first();
$location->delete();

參考資料

mongodb/laravel-mongodb MongoDB and Laravel Integration