附录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阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容