首頁  >  文章  >  後端開發  >  tp上mongo的配置

tp上mongo的配置

WBOY
WBOY原創
2016-07-30 13:29:421093瀏覽

tp已經支援mongodb的資料庫,以下是對mongo在tp上的設定和使用做一個詳細的說明。

(1)tp3.2.2版本中的/think/Model/mongoModel.class.php的原來的類別是存在bug的。我們需要在原來的類別中加入一些程式碼,修復bug。

<?php // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2010 http://topthink.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Model;
use Think\Model;
/**
 * MongoModel模型类
 * 实现了ODM和ActiveRecords模式
 */
class MongoModel extends Model{
    // 主键类型
    const TYPE_OBJECT   = 1; 
    const TYPE_INT      = 2;
    const TYPE_STRING   = 3;

    // 主键名称
    protected $pk               =   '_id';
    // _id 类型 1 Object 采用MongoId对象 2 Int 整形 支持自动增长 3 String 字符串Hash
    protected $_idType          =   self::TYPE_INT;
    // 主键是否自增
    protected $_autoinc         =   true;
    // Mongo默认关闭字段检测 可以动态追加字段
    protected $autoCheckFields  =   false;
    // 链操作方法列表
    protected $methods          =   array('table','order','auto','filter','validate');
    //数据库配置
    protected $connection       =   'DB_MONGO';

    /**
     * 利用__call方法实现一些特殊的Model方法
     * @access public
     * @param string $method 方法名称
     * @param array $args 调用参数
     * @return mixed
     */
    public function __call($method,$args) {
        if(in_array(strtolower($method),$this->methods,true)) {
            // 连贯操作的实现
            $this->options[strtolower($method)] =   $args[0];
            return $this;
        }elseif(strtolower(substr($method,0,5))=='getby') {
            // 根据某个字段获取记录
            $field   =   parse_name(substr($method,5));
            $where[$field] =$args[0];
            return $this->where($where)->find();
        }elseif(strtolower(substr($method,0,10))=='getfieldby') {
            // 根据某个字段获取记录的某个值
            $name   =   parse_name(substr($method,10));
            $where[$name] =$args[0];
            return $this->where($where)->getField($args[1]);
        }else{
            E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));
            return;
        }
    }

    /**
     * 获取字段信息并缓存 主键和自增信息直接配置
     * @access public
     * @return void
     */
    public function flush() {
        // 缓存不存在则查询数据表信息
        $fields =   $this->db->getFields();
        if(!$fields) { // 暂时没有数据无法获取字段信息 下次查询
            return false;
        }
        $this->fields   =   array_keys($fields);
        foreach ($fields as $key=>$val){
            // 记录字段类型
            $type[$key]    =   $val['type'];
        }
        // 记录字段类型信息
        if(C('DB_FIELDTYPE_CHECK'))   $this->fields['_type'] =  $type;

        // 2008-3-7 增加缓存开关控制
        if(C('DB_FIELDS_CACHE')){
            // 永久缓存数据表信息
            $db   =  $this->dbName?$this->dbName:C('DB_NAME');
            F('_fields/'.$db.'.'.$this->name,$this->fields);
        }
    }

    // 写入数据前的回调方法 包括新增和更新
    protected function _before_write(&$data) {
        $pk   =  $this->getPk();
        // 根据主键类型处理主键数据
        if(isset($data[$pk]) && $this->_idType == self::TYPE_OBJECT) {
            $data[$pk] =  new \MongoId($data[$pk]);
        }    
    }

    /**
     * count统计 配合where连贯操作
     * @access public
     * @return integer
     */
    public function count(){
        // 分析表达式
        $options =  $this->_parseOptions();
        return $this->db->count($options);
    }

    /**
     * 获取下一ID 用于自动增长型
     * @access public
     * @param string $pk 字段名 默认为主键
     * @return mixed
     */
    public function getMongoNextId($pk=''){
        if(empty($pk)) {
            $pk   =  $this->getPk();
        }
        return $this->db->mongo_next_id($pk);
    }

    /**
     * 新增数据
     * @access public
     * @param mixed $data 数据
     * @param array $options 表达式
     * @param boolean $replace 是否replace
     * @return mixed
     */
    public function add($data='',$opti {
        if(empty($data)) {
            // 没有传递数据,获取当前数据对象的值
            if(!empty($this->data)) {
                $data           =   $this->data;
                // 重置数据
                $this->data     = array();
            }else{
                $this->error    = L('_DATA_TYPE_INVALID_');
                return false;
            }
        }
        // 分析表达式
        $options    =   $this->_parseOptions($options);
        // 数据处理
        $data       =   $this->_facade($data);
        if(false === $this->_before_insert($data,$options)) {
            return false;
        }
        // 写入数据到数据库
        $result = $this->db->insert($data,$options,$replace);
        if(false !== $result ) {
            $this->_after_insert($data,$options);
            if(isset($data[$this->getPk()])){
                return $data[$this->getPk()];
            }
        }
        return $result;
    }

    // 插入数据前的回调方法
    protected function _before_insert(&$data,$options) {
        // 写入数据到数据库
        if($this->_autoinc && $this->_idType== self::TYPE_INT) { // 主键自动增长
            $pk   =  $this->getPk();
            if(!isset($data[$pk])) {
                $data[$pk]   =  $this->db->mongo_next_id($pk);
            }
        }
    }

    public function clear(){
        return $this->db->clear();
    }

    // 查询成功后的回调方法
    protected function _after_select(&$resultSet,$options) {
        array_walk($resultSet,array($this,'checkMongoId'));
    }

    /**
     * 获取MongoId
     * @access protected
     * @param array $result 返回数据
     * @return array
     */
    protected function checkMongoId(&$result){
        if(is_object($result['_id'])) {
            $result['_id'] = $result['_id']->__toString();
        }
        return $result;
    }

    // 表达式过滤回调方法
    protected function _options_filter(&$options) {
        $id = $this->getPk();
        if(isset($options['where'][$id]) && is_scalar($options['where'][$id]) && $this->_idType== self::TYPE_OBJECT) {
            $options['where'][$id] = new \MongoId($options['where'][$id]);
        }
    }

    /**
     * 查询数据
     * @access public
     * @param mixed $options 表达式参数
     * @return mixed
     */
     public function find($opti {
         if( is_numeric($options) || is_string($options)) {
            $id   =  $this->getPk();
            $where[$id] = $options;
            $options = array();
            $options['where'] = $where;
         }
        // 分析表达式
        $options =  $this->_parseOptions($options);
        $result = $this->db->find($options);
        if(false === $result) {
            return false;
        }
        if(empty($result)) {// 查询结果为空
            return null;
        }else{
            $this->checkMongoId($result);
        }
        $this->data = $result;
        $this->_after_find($this->data,$options);
        return $this->data;
     }

    /**
     * 字段值增长
     * @access public
     * @param string $field  字段名
     * @param integer $step  增长值
     * @return boolean
     */
    public function setInc($field,$step=1) {
        return $this->setField($field,array('inc',$step));
    }

    /**
     * 字段值减少
     * @access public
     * @param string $field  字段名
     * @param integer $step  减少值
     * @return boolean
     */
    public function setDec($field,$step=1) {
        return $this->setField($field,array('inc','-'.$step));
    }

    /**
     * 获取一条记录的某个字段值
     * @access public
     * @param string $field  字段名
     * @param string $spea  字段数据间隔符号
     * @return mixed
     */
    public function getField($field,$sepa=null) {
        $options['field']    =  $field;
        $options =  $this->_parseOptions($options);
        if(strpos($field,',')) { // 多字段
            if(is_numeric($sepa)) {// 限定数量
                $options['limit']   =   $sepa;
                $sepa   =   null;// 重置为null 返回数组
            }
            $resultSet = $this->db->select($options);
            if(!empty($resultSet)) {
                $_field = explode(',', $field);
                $field  = array_keys($resultSet[0]);
                $key =  array_shift($field);
                $key2 = array_shift($field);

         //解决参数$field 指定的字段顺序与数据库中记录字段顺序不一致时导致的返回结果$key不正确问题
                //2015-08-15 by bing
                if(!(array_search($_field[0], array_keys($resultSet[0]))===false)){
                    $key=$_field[0];
                    $key2=$_field[1];
                }

                $cols   =   array();
                $count  =   count($_field);
                foreach ($resultSet as $result){
                    $name   =  $result[$key];
                    if(2==$count) {
                        $cols[$name]   =  $result[$key2];
                    }else{
                        $cols[$name]   =  is_null($sepa)?$result:implode($sepa,$result);
                    }
                }
                return $cols;
            }
        }else{
            // 返回数据个数
            if(true !== $sepa) {// 当sepa指定为true的时候 返回所有数据
                $options['limit']   =   is_numeric($sepa)?$sepa:1;
            }            // 查找一条记录
            $result = $this->db->select($options);
            if(!empty($result)) {
                foreach ($result as $val){
                    if(strpos($field,'.')){
                        $tmp=explode('.', $field);
                        foreach ($tmp as $t){
                            $val=$val[$t];
                        }
                        $array[]    =   $val;
                    }else{
                        $array[]    =   $val[$field];
                    }
                }
                return 1 == $options['limit'] ? $array[0] : $array;
            }
        }
        return null;
    }

    /**
     * 执行Mongo指令
     * @access public
     * @param array $command  指令
     * @return mixed
     */
    public function command($command) {
        return $this->db->command($command);
    }

    /**
     * 执行MongoCode
     * @access public
     * @param string $code  MongoCode
     * @param array $args   参数
     * @return mixed
     */
    public function mongoCode($code,$args=array()) {
        return $this->db->execute($code,$args);
    }

    // 数据库切换后回调方法
    protected function _after_db() {
        // 切换Collection
       //bing 2015-8-15 获取数据表
     if(empty($this->dbName) && !empty($this->connection)){
            $db_c
            $this->dbName=$db_config['DB_NAME'];
        }
        $this->db->switchCollection($this->getTableName(),$this->dbName); 
     }
    /**
     * 得到完整的数据表名 Mongo表名不带dbName
     * @access public
     * @return string
     */
    public function getTableName() {
        if(empty($this->trueTableName)) {
            $tableName  = !empty($this->tablePrefix) ? $this->tablePrefix : '';
            if(!empty($this->tableName)) {
                $tableName .= $this->tableName;
            }else{
                $tableName .= parse_name($this->name);
            }
            $this->trueTableName    =   strtolower($tableName);
        }
        return $this->trueTableName;
    }
}
  

上面是一個修改之後的完整的mongo類別。

其中

(1)

<span style="color:#FF0000;">protected $connection       =   'DB_MONGO'; 是链接配置config对应的DB_mongo


(2)
</span>
  //解决参数$field 指定的字段顺序与数据库中记录字段顺序不一致时导致的返回结果$key不正确问题
                //2015-08-15 by bing
                if(!(array_search($_field[0], array_keys($resultSet[0]))===false)){
                    $key=$_field[0];
                    $key2=$_field[1];
                }

這一塊是加入進去的,建立資料庫的緩存

(3)

  //bing 2015-8-15 获取数据表
     if(empty($this->dbName) && !empty($this->connection)){
            $db_c
            $this->dbName=$db_config['DB_NAME'];
        }
        $this->db->switchCollection($this->getTableName(),$this->dbName);   
這一個函數在tp原來的MongoModel裡只會預設連結到MYSQL的設定dbname中去,現要作修改,如上圖所示。

二、在tp中設定DB_MONGO

(1)在config檔 中加入

'DB_MONGO'=>
		array(
			'DB_TYPE'   => 'mongo', // 数据库类型
			'DB_HOST'   => 'localhost', // 服务器地址
			'DB_NAME'   => 'test', // 数据库名
			'DB_USER'   => '', // 用户名
			'DB_PWD'    => '', // 密码
			'DB_PORT'   => '27017', // 端口 
	),
mongo預設是沒有認證的,所以使用者名稱和密碼為空。

(2)在MongoModel的新增

protected $connection       =   'DB_MONGO'; 是链接配置config对应的DB_mongo,就是上面的完整的Mongo类。

至此資料庫的設定已經完成。

三、安裝php_mongo驅動程式

在Windows上安裝驅動程式必須和自己所使用的php大版本想對應。

(1)下載對應版本的php_mongo。

(2)將php_mongo.dll複製到php的ext檔

(3)在php.ini中加入extension=php_mongo.dll

( 5)存取phpinfo,搜尋mongo

出現上面代表配置成功。

四、tp上mongo的CURD操作

(1)php連接mongo,建立實例化物件

$m=new \Think\Model\MongoModel('user');
其中「user」是集合,相當於mysql中的表。

(2)新增-add()

查詢和mysql基本上一樣,

example:

$data=array(
          "name"=>"李四",
          "addr"=>"深圳",
          "sex"=>"男",
          "info"=>array(
              "age"=>20,
              "phone"=>"12345",
            ),
        );
$result=$m->add($data);

這樣就將資料加入作為一個文檔,相當於mysql的一筆記錄。

(2)查詢——select(),getField()

如果要查詢剛才插進去的$data

$map['name']="李四",

$result=$m->where($map)->select();
查找的是整個文檔,傳回的是一個數組。
如圖
array(5) {
    ["_id"] => int(4)
    ["name"] => string(6) "李四"
    ["addr"] => string(6) "深圳"
    ["sex"] => string(3) "男"
    ["info"] => array(2) {
      ["age"] => int(20)
      ["phone"] => string(5) "12345"
    }
  }

如果要查一個字段,可以用getField();

$result=$m->where($map)->getField('info');
查出來如圖
array(2) {
  ["age"] => int(20)
  ["phone"] => string(5) "12345"
}
如果要查age這個鍵的值,直接
 $result=$m->where($map)->getField('info.age');
傳回int(20)

時間區段的查詢,要用數組形式查詢

例如文檔中有一個鍵“time”,要查找2015/815-2015/9/1之間的文檔。
$map=array('time'=>array('$gt'=>int,'$lt'=>int))
$result=$m->where($map)->select()
其中int代表時間戳。

(3)刪除-delete();

$result=$m->where($map)->delete();
這個delete的刪除是刪除整個文件。

(4)修改-save()

tp上mongo的配置

 $update['sex']=array('set','女');
 $m->where($map)->save($update);
結果:
array(5) {
    ["_id"] => int(4)
    ["name"] => string(6) "李四"
    ["addr"] => string(6) "深圳"
    ["sex"] => string(3) "女"
    ["info"] => array(2) {
      ["age"] => int(20)
      ["phone"] => string(5) "12345"
    }
例如修改內嵌文檔中的某個鍵的值,例如age
$update['info.age']=array('set',30);
$m->where($map)->save($update);

結果:
 array(5) {
    ["_id"] => int(3)
    ["name"] => string(6) "李四"
    ["addr"] => string(6) "深圳"
    ["sex"] => string(3) "女"
    ["info"] => array(2) {
      ["age"] => int(30)
      ["phone"] => string(5) "12345"
    }
  }

unset

例如要刪除某個鍵。



例如刪除文件中的addr鍵

看到已經沒有addr鍵了

push ——追加一個值到欄位(必須是陣列型別)裡面去



例如一個陣列(這裡不包含關係型陣列)

 $update['addr']=array('unset');
  $m->where($map)->save($update);
num是一個陣列,將資料加入陣列。


 array(4) {
    ["_id"] => int(3)
    ["name"] => string(6) "李四"
    ["sex"] => string(3) "女"
    ["info"] => array(2) {
      ["age"] => int(30)
      ["phone"] => string(5) "12345"
    }
  }
結果:

$data=array(
          "name"=>"李四",
          "addr"=>"深圳",
          "sex"=>"男",
          "info"=>array(
              "age"=>20,
              "phone"=>"12345",
            ),
          "num"=>array();
        );

   $result=$m->add($data);
如果要加數組
$update['num']=array('push',1);
$m->where($map)->save($update);
結果:


 array(5) {
    ["_id"] => int(3)
    ["name"] => string(6) "李四"
    ["sex"] => string(3) "女"
    ["info"] => array(2) {
      ["age"] => int(30)
      ["phone"] => string(5) "12345"
    }
   ["num"] => array(1) {
      [0] => int(1)
    }
  }

pull-根據值刪除欄位(

$update['num']=array('push',array('subject'=>'php'));
      $m->where($map)->save($update);
pull-根據值刪除欄位(組陣列裡的array('suject'=>'php')



🎝 '=>'php')


;

(5)統計——count()$result=$m->where($map)->count();至,以上方法都是經過實踐此測試的,mongo最常用的,能滿足業務要求的方法總結結束。如有什麼不對的地方,請指出!

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。 以上就介紹了tp上mongo的配置,包含了方面的內容,希望對PHP教學有興趣的朋友有幫助。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn