php7安装mongodb的扩展。
宝塔面板环境下php7.3默认安装了pecl扩展包, 安装的php7.4版本是默认不带pecl扩展包的。需要手动安装
php版本 < 7的时候 yum install php-pear 就可以
但是7.4 版本的不行,
$ wget http://pear.php.net/go-pear.phar
$ php go-pear.phar
安排完成后 pecl install mongodb 安装扩展
最后在php.ini 中添加 extension=mongodb.so 重启php后完成
在phpinfo中可以看到
构建一个操作类
我原本使用的是 hyperf2.0框架 基于 Task 模式 模式构建了 操作类,现在把他改成了纯粹的php类不在依赖hyperf框架。
<?php
declare(strict_types=1);
namespace App;
use MongoDB\Driver\BulkWrite;
use MongoDB\Driver\Manager;
use MongoDB\Driver\Query;
use MongoDB\Driver\Command;
use MongoDB\Driver\WriteConcern;
use MongoDB\BSON\UTCDateTime;
class MongoClass
{
public $manager;
protected function manager()
{
if ($this->manager instanceof Manager) {
return $this->manager;
}
if(env('MONGODB_URI','')){
$uri=env('MONGODB_URI');
}else{
$uri = 'mongodb://'.env('MONGODB_USER').':'.env('MONGODB_PASS').'@'.env('MONGODB_HOST').':'.env('MONGODB_PORT').'/'.env('MONGODB_DB');
}
print_r([$uri]);
return $this->manager = new Manager($uri, []);
}
public function insert(string $table, array $document,$type='count',$multi= false)
{
$writeConcern = new WriteConcern(WriteConcern::MAJORITY, 1000);
$bulk = new BulkWrite();
/*判断是否是批量添加*/
if(count($document)>1 && isset($document[1]) && is_array($document[1]) && is_array($document[0])){
foreach ($document as $arr){
$this->format($arr);
$_id=$bulk->insert($arr);
}
}elseif(count($document)==1 && is_array($document[0]) && count($document[0])>1){ /*批量添加 但是只有一行数据*/
$this->format($document[0]);
$_id=$bulk->insert($document[0]);
}else{
$this->format($document);
$_id=$bulk->insert($document);
}
$table=env('MONGODB_DB').'.'.env('APP_ENV','test').'_'.$table; /*增加库和前缀*/
$result = $this->manager()->executeBulkWrite($table, $bulk, $writeConcern);
if($type=='count'){
return $result->getInsertedCount(); /*返回插入数量*/
}elseif ($type=='_id'){
return $_id;
}
}
/**
*强制将 'time' 字段转换 ISOdate 时间对象
*/
private function format(&$dat){
/*时间戳 时间格式 转换成时间对象*/
if(isset($dat['time'])){
if(is_int($dat['time'])){
}elseif(is_numeric($dat['time'])){
$dat['time']=(int)$dat['time'];
}else{
$dat['time']=(int)strtotime($dat['time']);
if($dat['time']>1000000000){ /*验证时间格式*/
}else{ /*错误的时间格式*/
$dat['time']=(int)(microtime(TRUE)*1000); /*毫秒级*/
}
}
if($dat['time']<10000000000){ /*秒级时间戳*/
$dat['time']=$dat['time']*1000; /*毫秒级*/
}
}else{
$dat['time']=(int)(microtime(TRUE)*1000); /*毫秒级*/
}
$dat['time']=new UTCDateTime($dat['time']);
}
/**
* $type='query|command|update|update_multi|delete'
*/
public function query(string $table='', array $filter = [], array $options = [],$type='query')
{
if($table){
$table=env('MONGODB_DB').'.'.env('APP_ENV','test').'_'.$table;
}else{
$table=env('MONGODB_DB');
}
switch ($type){
case 'query'; /*普通结果集查询*/
$query = new Query($filter, $options);
$cursor = $this->manager()->executeQuery($table, $query);
return $cursor->toArray();
case 'command'; /*命令*/
if($filter['aggregate']){
$filter['aggregate']=env('APP_ENV','test').'_'.$filter['aggregate'];
}elseif($filter['count']){
$filter['count']=env('APP_ENV','test').'_'.$filter['count'];
}elseif($filter['distinct']){
$filter['distinct']=env('APP_ENV','test').'_'.$filter['distinct'];
}
$command = new Command($filter);
return $this->manager()->executeCommand($table, $command)->toArray();
case 'update'; /*更新*/
return $this->update($table,$filter,$options);
case 'update_multi'; /*批量更新*/
return $this->update_multi($table,$filter);
case 'delete'; /*删除*/
return $this->delete($table,$filter);
default:
return false;
}
}
/**
* $update=['$set'=>[],'$inc'=>[]]
*/
public function update(string $db, array $where = [], $update = [], $upsert = false)
{
$writeConcern = new WriteConcern(WriteConcern::MAJORITY, 1000); /* MAJORITY 抛出网络错误异常 最大等待1000毫秒*/
$bulk = new BulkWrite(['ordered' => true]); /* ordered 有序还是无序执行操作。默认值true */
$up_dat=[];
if(isset($update['$inc'])){
$up_dat['$inc']=$update['$inc']; /*自增 自减*/
}
if(isset($update['$set'])){
$up_dat['$set']=$update['$set']; /*set赋值*/
}
if(!$up_dat){ /*就默认传入的数组是 set赋值*/
$up_dat['$set']=$update;
}
$bulk->update($where,$up_dat, ['multi' => false, 'upsert' => $upsert]);
/*multi(默认为false): 如果multi=true,则修改所有符合条件的行,否则只修改第一条符合条件的行 upsert(默认为false):如果upsert=true,如果query找到了符合条件的行,则修改这些行,如果没有找到,则追加一行符合query和obj的行。如果upsert为false,找不到时,不追加*/
$result = $this->manager()->executeBulkWrite($db, $bulk,$writeConcern);
$res = $result->getModifiedCount(); /*返回更新的现有文档数*/
//$u = $result->getUpsertedCount(); /*返回由 upsert 插入的文档数*/
//$res = $m>$u ? $m:$u;
if($res>0){
return 1;
}else{
return 0;
}
}
/**
* $update[] =['where'=>[],'update'=>['$set'=>[],'$inc'=>[]]]
*/
public function update_multi(string $db, $update = [])
{
if(is_array($update) && count($update)>0){
$writeConcern = new WriteConcern(WriteConcern::MAJORITY, 1000); /* MAJORITY 抛出网络错误异常 最大等待1000毫秒*/
$bulk = new BulkWrite(['ordered' => true]); /* ordered 有序还是无序执行操作。默认值true */
$updateOptions = ['multi' => false, 'upsert' => 'true']; /*multi 是否只修改第一个匹配 upsert */
foreach ($update as $val){
$bulk->update($val['where'],$val['update'],$updateOptions);
}
$result = $this->manager()->executeBulkWrite($db, $bulk,$writeConcern);
$res = $result->getModifiedCount();
if($res>0){
return 1;
}else{
return 0;
}
}else{
return 0;
}
}
/**
*
*/
public function delete(string $db, array $where = [])
{
$writeConcern = new WriteConcern(WriteConcern::MAJORITY, 1000);
$bulk = new BulkWrite();
$bulk->delete($where, ['limit' => 0]); /*limit 1 删除第一条匹配数据 0 删除所有匹配数据*/
$result = $this->manager()->executeBulkWrite($db, $bulk,$writeConcern);
$m = $result->getModifiedCount();
$u = $result->getUpsertedCount();
$res = $m>$u ? $m:$u;
if($res>0){
return 1;
}else{
return 0;
}
}
}
这个类中 manager方法连接数据库
insert 方法使用 $this->manager()->executeBulkWrite() 实现插入功能;
insert 方法参数 $document 就是一个行记录的数组,$table 就是集合名称,$type 可以决定返回值 是插入的个数还是最后一个插入成功的主键 _id;
这个类中 query 方法我封装了 query|command|update|update_multi|delete 5种操作。
$options=['projection' => ['_id' => 0,'user'=>1],'sort' => ['_id' => -1],'limit'=>$limit,'skip'=>$start];
参数 projection 映射 类似mysql中的 select 就是要显示哪个字段。0表示不显示 1代表显示 如果没有1 则其余的字段都会显示。
参数 sort 是排序 -1 desc 1 asc 多个字段也是可以的,limit skip和mysql中功能一样
最后细说 $filter参数
$filter['_id']=new \MongoDB\BSON\ObjectId("60779eeb99cc037490518d33");
MongoDB的主键 _id是一个对象,不能直接使用字符搜索 必须需要 ObjectId 转换成对象.
$filter['user_id']=1001 这是最普通的等于搜索
$filter['time']=1618656124 //如果你存储时间是用的时间戳
$filter['time']="2021-04-17 18:42:03" //如果你存储时间是用的字符
$filter['time']=new \MongoDB\BSON\UTCDateTime($time*1000)
//$time 是一个时间戳
insert 方法中 获取当前时间戳对应的时间对象 $document['time']=new UTCDateTime();
$val=['$regex'=>"^a.*z$",'$options'=>'i'];
这个是正则模糊匹配, 能支持三种参数, ^a 以a开始, .* 任意字符, z$ 以z结束。
$options 必须要全小写 对应参数 i或者$i 都可以,代表大小写敏感。 这个参数很多网站上 都是 $Options=>'$i' 大小写,坑了不少人。
$filter['time']=['$gte'=>new UTCDateTime($time0*1000),'$lte'=>new UTCDateTime($time1*1000)]; 这个就相当于 mysql的 BETWEEN AND 包含边界的范围。
其中
(>) 大于 - $gt (>=) 大于等于 - $gte
(<) 小于 - $lt (<= ) 小于等于 - $lte
这些就是最基本的查询
$filter['type']=['$in'=>[1,2,3]] 类似mysql in
$filter['type']=['$nin'=>[1,2,3]] 类似mysql not in
$filter['type']=null 类似mysql is_null
$filter['type']=['$ne'=>null] 类似mysql not is_null
$filter['type']='' 空字符
$filter['type']=['$ne'=>''] 非空字符
$filter['type']=['$exists'=>true] 字段存在
$filter['type']=['$exists'=>false] 字段不存在
$filter['result']=['$type'=>"int"] 字段类型是int
$filter['result']=['$not'=>['$type'=>"string"]] 字段类型不是 string
double array timestamp bool object undefined null
关于mongodb支持的字段类型可以网上搜索
MongoDB $type 操作符
$filter 每一项之间都是 and关系,也可以指定是and 或or。
$filter['$and'=>['type'=>null,'status'=>2],'$or'=>['type'=>null,'status'=>1]];
以上 类似 mysql where 中 (type = null and status==2) and (type = null or status==2) ,
$and 的子项 都是 and 关系,$or子项之间都是 or关系, $and 与$or都属于$filter的子项 默认都是 and关系。
$and和$or的子项都是可以继续嵌套$and和$or。
Command 命令
搜索一个库下集合
$cmd=['listCollections' => 1,'filter'=>['name'=>['$regex'=>'^user_log_']],'nameOnly'=>true];
$model->query('',$cmd,[],'command');
$cmd中 'listCollections' => 1 代表要查询库下面啊的集合 filter 是过滤条件 nameOnly 是忽略账号权限。
这个不是针对某个集合的操作 是针对当前数据库的操作。query参数第一个可以留空 我封装的方法会自动识别当前db,你也可以传入某个db。
统计一个集合下的数据量 类似mysql 的 count
$cmd=["count" => $table,"query" =>$filter];
$model->query('',$cmd,[],'command');
$cmd中 count指定某个集合 query 是对集合进行过滤 $filter和搜索中的使用方法一样。
update 操作
$model->query($table,$filter,$arr,'update');
这个方法中 参数 $filter 和查询一样。
$arr=['type'=>5,'$inc'=>['num'=>1]]; type字段设置成5,num 字段自增1 如果 -1 就是自减
mongodb的基本操作就这么多了
还有聚合类操作。下一节会继续细说。
防止误删除啊a