MongoDB 是一个基于分布式文件存储的数据库,也介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的
它支持的数据结构非常松散,是类似 json 的 bson 格式,因此可以存储比较复杂的数据类型
Mongo 最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
使用 MongoDB 的用户很多,因为它的文档型存储一些变化的内容很方便
在 PHP5 及以前,官方提供了两个扩展,Mongo 和 MongoDB,其中 Mongo 是对以 MongoClient
等几个核心类为基础的类群进行操作,封装得很方便,所以基本上都会选择 Mongo 扩展。
但是随着 PHP 升级到 PHP7,官方不再支持 Mongo 扩展,只支持 MongoDB,所以怎么把 Mongo 无缝替换成 MongoDB 成为了一个亟待解决的问题
MongoDB 引入了命名空间,但是功能封装非常差,如果非要用原生的扩展,几乎意味着写原生的 Mongo 语句
这种想法很违背 ORM 的初衷:简化 DB 操作带来的语法问题而专注逻辑优化
MongoDB 驱动
使用新驱动的部分代码如下:
MongoDbDriver.phpuse MongoDB\Driver\WriteConcern; class MongoDb { //属性略 public function __construct($config) { //解析拼接配置过程略 $this->mongodb = new \MongoDB\Driver\Manager($mongoServer); $this->database = $config['database']; $this->collection = $config['collection']; $this->bulk = new \MongoDB\Driver\BulkWrite(); $this->writeConcern = new WriteConcern(WriteConcern::MAJORITY, 100); } public function insert($data = []) { $this->bulk->insert($data); $result = $this->mongodb->executeBulkWrite( "$this->database.$this->collection", $this->bulk, $this->writeConcern ); return $result->getInsertedCount(); } public function delete($where = [], $limit = 1) { $this->bulk->delete($where, ['limit' => $limit]); $result = $this->mongodb->executeBulkWrite( "$this->database.$this->collection", $this->bulk, $this->writeConcern ); return $result->getDeletedCount(); } public function update($where = [], $update = [], $upsert = false) { $this->bulk->update($where, ['$set' => $update], ['multi' => true, 'upsert' => $upsert]); $result = $this->mongodb->executeBulkWrite( "$this->database.$this->collection", $this->bulk, $this->writeConcern ); return $result->getModifiedCount(); } public function query($where = [], $option = []) { $query = new \MongoDB\Driver\Query($where, $option); $result = $this->mongodb->executeQuery("$this->database.$this->collection", $query); return json_encode($result); } }
这样的语法和之前差异太大,改动不方便
在这种情况之下,MongoDB 官方为了方便使用,增加市场占有率,推出了基于 MongoDB 扩展的库:mongo-php-library
该库的详细文档见:docs.mongodb.com
composer 下载:
composer require mongodb/mongodb
MongoDB 操作包与旧 Mongo 对比
连接
//old
new MongoClient();
//new
new MongoDB\Client();
新增
//old
$collention->insert($array, $options);
//new
$resultOne = $collention->insertOne($array, $options);//单
$lastId = $resultOne->getInsertedId();
$resultMany = $collention->insertMany($array, $options);//多
$count = $resultMany->getInsertedCount();
修改
//old
$collention->update($condition, [
'$set' => $values
,[
'multiple' => true//多条,单条false
]);
//new
$collection->updateOne(
['state' => 'ny'],
['$set' => ['country' => 'us']]
);
$updateResult = $collection->updateMany(
['state' => 'ny'],
['$set' => ['country' => 'us']]
);
$count = $updateResult->getModifiedCount();
查询
//old
$cursor = $collection->find($condition, [
'name' => true//指定字段
]);
$cursor->skip(5);
$cursor->limit(5);
$cursor->sort([
'time' => -1
]);
//new
$cursor = $collection->find($condition, [
'skip' => 5,
'limit' => 5,
'sort' => [
'time' => -1
],//排序
'projection' => [
'name' => 1//指定字段
]
]);
删除
//old
$collention->remove($condition, [
'justOne' => false//删单条
]);
$collention->remove([]);//删所有
//new
$result = $collention->deleteOne($condition, $options);
$collention->deleteMany($condition, $options);
$result->getDeletedCount();
有业务可能需要以类似 MySQL 的自增 ID 来处理数据,PHP5 可能使用的 findAndModify()
方法来查询并修改:
$collention->findAndModify([
'_id' => $tableName//我在自增表中用其它的表名作主键
], [
'$inc' => ['id' => 1]//自增
], [
'_id' => 0
], [
'new' => 1//返回修改后的结果,默认是修改前的
]);
现在使用 MongoDB 库的话需要修改为:
$collention->findOneAndUpdate([
'_id' => $tableName
], [
'$inc' => ['id' => 1]
], [
'projection' => ['id' => 1],
'returnDocument' => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER
]);
类似的还有 findOneAndDelete()
findOneAndReplace()
,更多内容可见 findOneAndUpdate文档
ODM
在开发一个业务中,由于条件非常复杂,会出现各种 $and
$or
嵌套,想添加新条件时容易出问题
所以在基类中引入了 ODM,支持链式查询的写法,使查询条件直观易理解
改造了项目中老的 Mongo 操作类,引入了新 Trait
MongoODMTrait.phptrait MongoODM { public $mongoOdm; public function connectOdm($db) { //解析拼接配置过程略 $client = new \Sokil\Mongo\Client($mongoServer); $database = $client->getDatabase($config['database']); $this->mongoOdm = new MongoOdm($database); } }
在原有操作类中新增一行 ODM 连接
Mongo.phpuse MongoODM; $this->connectOdm(self::Key);
查询时部分示例代码如下:
QueryTest.php$collection = $bean->mongoOdm->collection; $builder = $bean->mongoOdm->find(); $builder->whereIn('sale_id', [1,2,3]); $builder->where('identity', ['$bitsAnySet' => [$bit]]); $builder->whereAnd( $collection->expression()->whereOr( $collection->expression()->whereGreaterOrEqual('last_time', strtotime(date('Y-m-d'))), $collection->expression()->whereLike('desc', "{$desc}", true) ) ); $total = $builder->count(); $result = $builder->fields(explode(','), $fields) ->sort($sort) ->limit($size) ->skip($offset) ->findAll();