本文分享一個功能完整的 PHP MongoDB 操作類 HMongodb,支援多伺服器連線、自動負載均衡、單例模式管理,涵蓋 CRUD、索引管理、錯誤處理等核心功能,適合直接整合至專案中使用。
safe = true 確認寫入成功<?php
class HMongodb {
private $mongo;
private $curr_db_name;
private $curr_table_name;
private $error;
/** 取得單例實例
* @param array|string $mongo_server 伺服器列表
* @param array $flag 選項:tag(標識), force(強制新建)
* @return HMongodb|false
*/
public function getInstance($mongo_server, $flag = []) {
static $mongodb_arr;
$flag['tag'] = $flag['tag'] ?? 'default';
if (($flag['force'] ?? false) === true) {
$mongo = new HMongodb($mongo_server);
$mongodb_arr[$flag['tag']] = $mongo;
return $mongo;
}
if (isset($mongodb_arr[$flag['tag']]) && is_resource($mongodb_arr[$flag['tag']])) {
return $mongodb_arr[$flag['tag']];
}
$mongo = new HMongodb($mongo_server);
$mongodb_arr[$flag['tag']] = $mongo;
return $mongo;
}
/** 建構子:支援多伺服器與負載均衡 */
private function __construct($mongo_server, $connect = true, $auto_balance = true) {
// 解析伺服器字串,支援 "host:port" 或陣列
if (is_array($mongo_server)) {
$count = count($mongo_server);
if ($count > 1 && $auto_balance) {
$prior = rand(1, $count);
$keys = array_rand($mongo_server, $count);
$server_str = $mongo_server[$prior - 1];
foreach ($keys as $k) {
if ($k != $prior - 1) $server_str .= ',' . $mongo_server[$k];
}
} else {
$server_str = implode(',', $mongo_server);
}
} else {
$server_str = $mongo_server;
}
try {
$this->mongo = new Mongo($server_str, ['connect' => $connect]);
} catch (MongoConnectionException $e) {
$this->error = $e->getMessage();
return false;
}
}
/** 手動連線 */
public function connect() {
try {
$this->mongo->connect();
return true;
} catch (MongoConnectionException $e) {
$this->error = $e->getMessage();
return false;
}
}
/** 選擇資料庫 */
public function selectDb($dbname) {
$this->curr_db_name = $dbname;
}
/** 建立索引 */
public function ensureIndex($table_name, $index, $index_param = []) {
$dbname = $this->curr_db_name;
$index_param['safe'] = 1;
try {
$this->mongo->$dbname->$table_name->ensureIndex($index, $index_param);
return true;
} catch (MongoCursorException $e) {
$this->error = $e->getMessage();
return false;
}
}
/** 插入文檔 */
public function insert($table_name, $record) {
$dbname = $this->curr_db_name;
try {
$this->mongo->$dbname->$table_name->insert($record, ['safe' => true]);
return true;
} catch (MongoCursorException $e) {
$this->error = $e->getMessage();
return false;
}
}
/** 統計文檔數 */
public function count($table_name) {
$dbname = $this->curr_db_name;
return $this->mongo->$dbname->$table_name->count();
}
/** 更新文檔 */
public function update($table_name, $condition, $newdata, $options = []) {
$dbname = $this->curr_db_name;
$options['safe'] = 1;
$options['multiple'] = $options['multiple'] ?? 0;
try {
$this->mongo->$dbname->$table_name->update($condition, $newdata, $options);
return true;
} catch (MongoCursorException $e) {
$this->error = $e->getMessage();
return false;
}
}
/** 刪除文檔 */
public function remove($table_name, $condition, $options = []) {
$dbname = $this->curr_db_name;
$options['safe'] = 1;
try {
$this->mongo->$dbname->$table_name->remove($condition, $options);
return true;
} catch (MongoCursorException $e) {
$this->error = $e->getMessage();
return false;
}
}
/** 查詢多筆 */
public function find($table_name, $query_condition, $result_condition = [], $fields = []) {
$dbname = $this->curr_db_name;
$cursor = $this->mongo->$dbname->$table_name->find($query_condition, $fields);
if (!empty($result_condition['start'])) $cursor->skip($result_condition['start']);
if (!empty($result_condition['limit'])) $cursor->limit($result_condition['limit']);
if (!empty($result_condition['sort'])) $cursor->sort($result_condition['sort']);
$result = [];
try {
while ($cursor->hasNext()) {
$result[] = $cursor->getNext();
}
} catch (MongoConnectionException|MongoCursorTimeoutException $e) {
$this->error = $e->getMessage();
return false;
}
return $result;
}
/** 查詢單筆 */
public function findOne($table_name, $condition, $fields = []) {
$dbname = $this->curr_db_name;
return $this->mongo->$dbname->$table_name->findOne($condition, $fields);
}
/** 取得錯誤訊息 */
public function getError() {
return $this->error;
}
}
<?php
// 初始化(單伺服器)
$mongo = HMongodb::getInstance("127.0.0.1:27017");
// 或多伺服器負載均衡
// $mongo = HMongodb::getInstance(["127.0.0.1:27017", "127.0.0.1:27018"]);
$mongo->selectDb("test_db");
// 建立唯一索引
$mongo->ensureIndex("users", ["email" => 1], ['unique' => true]);
// 插入
$mongo->insert("users", ["email" => "user@example.com", "name" => "張三"]);
// 更新(upsert)
$mongo->update("users", ["email" => "user@example.com"], ["name" => "李四"], ["upsert" => 1]);
// 分頁查詢
$list = $mongo->find("users", ["age" => ['$gt' => 18]], [
'start' => 0,
'limit' => 10,
'sort' => ["created_at" => -1]
]);
// 單筆查詢
$user = $mongo->findOne("users", ["email" => "user@example.com"]);
// 刪除
$mongo->remove("users", ["email" => "user@example.com"], ["justOne" => 1]);
// 錯誤處理
if ($mongo->getError()) {
error_log("MongoDB Error: " . $mongo->getError());
}
Mongo 擴展(PHP 5.x 時代)。現代專案(PHP 7+)請改用官方 mongodb/mongodb 套件(Composer 安裝),新版 API 採用 MongoDB\Client、MongoDB\Database、MongoDB\Collection 等命名空間類別,功能更強大且持續維護中。
| 舊版 (Mongo) | 新版 (mongodb/mongodb) |
|---|---|
| new Mongo("localhost:27017") | new MongoDB\Client("mongodb://localhost:27017") |
| $mongo->db->collection | $client->db->collection |
| insert($doc, ['safe'=>true]) | insertOne($doc) / insertMany($docs) |
| update($cond, $new, ['multiple'=>1]) | updateMany($cond, ['$set' => $new]) |
| find($cond)->limit(10) | find($cond, ['limit' => 10]) |
| ensureIndex($keys, $opts) | createIndex($keys, $opts) |
此類別雖屬舊版實作,但其單例管理、多伺服器容錯、錯誤封裝等設計思路仍具參考價值,可作為理解 MongoDB PHP 驅動封裝模式的教學案例。