附錄B: 使用MongoDb

MongoDB 是由C++語言編寫的開源數據庫系統,是一個基于分布式文件存儲的非關系型數據庫(NoSQL),旨在為WEB應用提供可擴展的高性能數據存儲解決方案。

ThinkPHP5.0核心并不支持MongoDb,但官方提供了mongo驅動擴展,通過擴展可以很方便的和普通數據庫一樣使用MongoDb,本篇我們就來給大家講解下如何安裝和使用MongoDb,主要包含:

安裝環境及配置

這里給大家簡單介紹下最新版本的MongoDb運行環境的安裝及ThinkPHP中的配置。

ThinkPHP5.0Mongo擴展的運行環境要求如下:

  • MongoDb 3.0+
  • MongoDB PHP擴展 1.0+

第一步:安裝MongoDb

關于如何安裝MongoDb本文不想深入探討,相信你需要使用MongoDb的時候已經掌握了安裝過程,否則也不會選擇作為你的數據存儲。如果你已經安裝了MongoDb的話,請略過這一步。

安裝最新版本的MongoDb很簡單,直接到
https://www.mongodb.com/download-center 下載對應的系統安裝文件,通常社區版就可以了,很多主機服務本身也提供了MongoDb支持。

安裝完后,MongoDB將數據目錄存儲在根目錄的data/db 目錄下。但是這個數據目錄不會主動創建,我們在安裝完成后需要創建它。建議把mongodbbin目錄加入path環境變量,方便在命令行下面執行命令。

使用mongod命令啟動MongoDb服務器,使用mongo命令進入MongoDb管理后臺,新手推薦使用Robomongo客戶端工具進行可視化管理。

在默認情況下,mongod是監聽在0.0.0.0之上的,任何客戶端都可以通過27017端口直接連接,且沒有認證。好處是學習階段上手快,不過線上部署的時候一定要注意mongodb的安全配置準則,在此就不再細說了。

系統默認的文檔位于system下的local,為了測試方便,我們可以創建一個demo文檔集合。

第二步:安裝PHP擴展(重要

要通過PHP操作MongoDb,就需要裝PHP的mongo擴展,訪問 http://pecl.php.net/package/mongodb ,選擇最新的版本(截至本書寫作的時候最新版本為1.2.5)即可,已經支持最新的PHP7.1版本。

windows環境為例,針對不同的PHP提供了不同的預編譯版本,選擇對應的版本下載解壓后把php_mongodb.dll文件放入PHP安裝目錄下的擴展目錄(通常是ext),然后在php.ini文件中添加

extension=php_mongodb.dll

重啟你的web服務器后,使用phpinfo()驗證是否已經支持mongodb,如果發現如圖所示,說明mongodb擴展已經安裝完成。

image

第三步:安裝ThinkPHP5擴展

首先確認你使用的是最新版本的5.0,然后使用Composer安裝:

composer require topthink/think-mongo=1.*

5.0版本的核心框架支持think-mongo擴展的版本是1.* 版本

如果你下載的是官方提供的5.0完整版,這一步可以略過。

官方的mongo擴展是基于PHP的新版MongoDB driver封裝,而并非使用舊版的MongoClient類庫,該驅動需要PHP5.4+版本。

第四步:配置mongo

在正式使用MongoDb之前,需要修改數據庫配置文件中的相關參數:

    // 數據庫類型
    'type'           => '\think\mongo\Connection',
    // 服務器地址
    'hostname'       => '127.0.0.1',
    // 集合名
    'database'       => 'demo',
    // 用戶名
    'username'       => '',
    // 密碼
    'password'       => '',
    // 端口
    'hostport'       => '',

默認安裝的mongodb是沒有用戶名和密碼的,可以留空。如果你的服務器安裝的mongodb提供了用戶名和密碼認證,請自行修改。MongoDb一樣支持分布式設置,設置方法和Mysql的分布式設置一致。

下面我們就來開啟MongoDb的查詢之旅吧。

使用查詢構造器

大部分查詢構造器的方法都可以直接使用,從下面的CURD示例代碼可以看出和普通的數據庫查詢并無大的區別。

// 創建操作
Db::table('user')->insert([
    'name'  => 'thinkphp',
    'email' => 'thinkphp@qq.com',
]);

// 查詢操作
$user = Db::table('user')
    ->where('name', 'thinkphp')
    ->where('email', 'like', 'think')
    ->find();
dump($user);

// 更新操作
Db::table('user')
    ->where('name','thinkphp')
    ->update([
        'name' => 'topthink',
    ]);

// 刪除操作
Db::table('user')
    ->where('name','thinkphp')
    ->delete();

開啟調試模式的話,一樣可以在SQL日志中生成mongo查詢語句,不過該語法僅供參考,并不能嚴格確保在mongo中執行。

dump($user)的輸出結果類似于下面:

array (size=3)
  '_id' => 
    object(MongoDB\BSON\ObjectID)[12]
      public 'oid' => string '589461c0fc122812b4007411' (length=24)
  'name' => string 'thinkphp' (length=8)
  'email' => string 'thinkphp@qq.com' (length=15)

關于主鍵

上面的例子中,MongoDb會自動添加_id字段而且作為主鍵,該主鍵數據是一個MongoDB\BSON\ObjectID對象實例。

為了方便查詢,系統做了封裝,該主鍵的值可以直接當作字符串使用,因此下面的查詢是有效的:

// 查詢操作
$user = Db::table('user')
    ->where('_id','589461c0fc122812b4007411')
    ->find();
// 或者直接使用
$user = Db::table('user')
    ->find('589461c0fc122812b4007411');

為了保持和Mysql一致的主鍵命名習慣,系統提供了一個數據庫配置參數pk_convert_id可以強制把_id轉換為id進行操作。

// 強制把_id轉換為id
'pk_convert_id'  => true,

設置后,就可以把id當成_id來使用

// 查詢操作
$user = Db::table('user')
    ->where('id','589461c0fc122812b4007411')
    ->find();
dump($user);

輸出結果為:

array (size=3)
  'name' => string 'thinkphp' (length=8)
  'email' => string 'thinkphp@qq.com' (length=15)
  'id' => string '589461c0fc122812b4007411' (length=24)

原來的_id已經變成id,而且是一個字符串類型。

當然,如果需要你仍然可以添加一個額外的主鍵id而不使用MongoDb默認的_id字段,但并不建議這么做。

方法變化和差異

除了常規的CURD方法之外,包括valuecolumnsetIncsetDecsetFieldpaginate等方法仍然被支持,更新的時候也支持dataincdec方法,聚合查詢方法除了count方法之外其它暫時不支持。

think-mongo擴展1.6版本開始支持聚合查詢,可以直接使用包括max/min/sum/avg等查詢方法。

由于數據庫自身的原因,以下鏈式方法在MongoDb中不再支持(或者無效):

不再支持的方法
view
join
alias
group
having
union
lock
strict
sequence
force
bind
partition

針對了MongoDb的特殊性增加了如下鏈式操作方法:

方法 描述
skip 設置skip
awaitData 設置awaitData
batchSize 設置batchSize
exhaust 設置exhaust
modifiers 設置modifiers
noCursorTimeout 設置noCursorTimeout
oplogReplay 設置oplogReplay
partial 設置partial
maxTimeMS 設置maxTimeMS
slaveOk 設置slaveOk
tailable 設置tailable
writeConcern 設置writeConcern

并且fetchPdo方法改為fetchCursor

查詢表達式

MongoDb的查詢表達式和Mysql有所區別,并非完全一致。

支持的查詢表達式(不區分大小寫)包括:

表達式 含義
EQ、= 等于(=)
NEQ、<> 不等于(<>)
GT、> 大于(>)
EGT、>= 大于等于(>=)
LT、< 小于(<)
ELT、<= 小于等于(<=)
MOD MOD查詢
ALL 滿足所有條件
LIKE 模糊查詢
TYPE 字段類型查詢
[NOT] BETWEEN (不在)區間查詢
[NOT] IN (不在)IN 查詢
EXISTS 查詢字段是否存在
SIZE 元素長度查詢
EXISTS 查詢字段是否存在
EXP 使用MongoDB\BSON\Javascript對象查詢
REGEX 使用MongoDB\BSON\Regex對象查詢
NEAR 經緯度查詢
> time 時間比較
< time 時間比較
between time 時間比較
notbetween time 時間比較

使用模型查詢

一樣可以使用模型的CURD操作MongoDb,下面是一個使用示例。

// 創建操作
$user = new User;
$user->name  = 'thinkphp';
$user->email = 'thinkphp@qq.com';
$user->save();

// 查詢操作
$user = User::where('name', 'thinkphp')
    ->where('email', 'like', 'think')
    ->find();
dump($user->toArray());

// 更新操作
$user->name = 'topthink';
$user->save();

// 刪除操作
$user->delete();

甚至你還可以使用模型關聯操作,包括軟刪除功能。

Mongo原生查詢

系統提供了幾個基礎查詢方法,僅供熟悉MongoDb語法的用戶使用。

query (collection,query)

collection:表示當前查詢的集合
query:是一個\MongoDB\Driver\Query對象,詳細用法可以參考官方手冊

代碼示例如下

$filter = [
    'author' => 'bjori',
    'views' => [
        '$gte' => 100,
    ],
];

$options = [
    /* Only return the following fields in the matching documents */
    'projection' => [
        'title' => 1,
        'article' => 1,
    ],
    /* Return the documents in descending order of views */
    'sort' => [
        'views' => -1
    ],
);

$query = new MongoDB\Driver\Query($filter, $options);
Db::query('demo.user', $query);

execute (collection,bulk)

collection:表示當前查詢的集合
bulk:是一個\MongoDB\Driver\BulkWrite對象,詳細用法可以參考官方手冊

command (command,dbName)

command:是一個\MongoDB\Driver\Command對象,詳細用法參考官方手冊

dbName:當前操作的數據庫名稱,留空表示當前數據庫

除此之外,系統還封裝了一個cmd方法可以直接執行字符串格式的mongo命令,例如:

// 列出當前的集合
$collections = Db::cmd('listCollections');

更多的mongo命令參考MongoDb官方手冊。

總結

Mongo擴展提供了和核心內置數據庫一般的查詢體驗,并且支持:

  • 數據庫的基本CURD操作;
  • 數據庫分布式;
  • 模型的CURD操作;
  • 模型關聯操作(個別特性不支持);
  • 數據庫事件;
  • 模型事件;
  • 原生MongoDb查詢語法;

上一篇:附錄A:常見問題
下一篇:附錄C:數據庫配置清單

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容