php7 mongodb 使用(二)原生驱动 增删改查和统计

7 篇文章 0 订阅

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hangbobo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值