>  기사  >  백엔드 개발  >  tp의 mongo 구성

tp의 mongo 구성

WBOY
WBOY원래의
2016-07-30 13:29:421140검색

TP는 이미 mongodb 데이터베이스를 지원하고 있습니다. 다음은 TP에서의 mongo 구성 및 사용에 대한 자세한 설명입니다.

(1) tp3.2.2 버전의 /think/Model/mongoModel.class.php 원본 클래스에 버그가 있습니다. 버그를 수정하려면 원래 클래스에 일부 코드를 추가해야 합니다.

<?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;
    }
}
  

위는 수정된 완전 몽고 클래스입니다.

그 중

(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에만 연결됩니다. 이제 위와 같이 수정해야 합니다.

2. tp

에서 DB_MONGO 구성 (1) 구성 파일에

'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类。

을 추가하면 이제 데이터베이스 구성이 완료되었습니다.

3. php_mongo 드라이버 설치

Windows에 드라이버를 설치할 때 사용 중인 PHP의 대형 버전과 일치해야 합니다.

(1) 해당 버전의 php_mongo를 다운로드합니다.

(2) php_mongo.dll을 php의 확장 파일에 복사합니다.

(3) php.ini .dll에 Extension=php_mongo를 추가합니다.

(4) Apache 다시 시작

(5) phpinfo 방문하여 mongo 검색

위의 내용이 나타나면 설정에 성공한 것입니다.

4. TP에서 mongo의 CURD 작업

(1) PHP는 mongo에 연결하고 인스턴스화된 객체를 생성합니다

$m=new \Think\Model\MongoModel('user');
여기서 "user"는 테이블과 동일합니다. mysql에서 .

(2) 추가 - add()

쿼리는 기본적으로 mysql과 동일합니다.

예:

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

이런 방식으로 데이터는 mysql의 레코드와 동일한 문서로 추가됩니다.

(2) Query - select(), getField()

방금 삽입한 $data를 조회하고 싶은 경우

$map['name' ] ="lee思",

$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) 삭제-삭제();

$result=$m->where($map)->delete();
이 삭제는 문서 전체를 삭제하는 것입니다.

(4) 수정 - save()


set

예를 들어 문서의 sex=>'male'을 sex=>'"female"

결과:
 $update['sex']=array('set','女');
 $m->where($map)->save($update);
예를 들어 age
array(5) {
    ["_id"] => int(4)
    ["name"] => string(6) "李四"
    ["addr"] => string(6) "深圳"
    ["sex"] => string(3) "女"
    ["info"] => array(2) {
      ["age"] => int(20)
      ["phone"] => string(5) "12345"
    }
$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 키를 삭제하세요.

 $update['addr']=array('unset');
  $m->where($map)->save($update);
결과:

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

보시다시피 addr 키가 없습니다

push - 필드에 값을 추가합니다(배열 유형이어야 함)

예를 들어 배열(관계형 배열은 여기에 포함되지 않음)

num은 배열이므로 데이터를 수정하고 추가합니다.
$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)
    }
  }

$update['num']=array('push',array('subject'=>'php'));
      $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(2) {
      [0] => int(1)
      [1] => array(1) {
        ["subject"] => string(3) "php"
      }
    }
  }

풀 - 값을 기준으로 필드(배열 필드여야 함)에서 값을 삭제합니다.

이제 값을 삭제하려고 합니다. 방금 num 배열 배열에 추가했습니다('suject'=>'php')

결과:
 $update['num']=array('pull',array('subject'=>'php'));
 $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)
    }
  }

배열('suject'=>)이 없음을 확인할 수 있습니다. ;num 배열의 'php' );

(5) 통계 - count()

$result=$m->where($map)->count();

이 시점에서 위의 방법은 실제로 테스트되었으며 비즈니스 요구 사항을 충족할 수 있는 mongo에서 가장 일반적으로 사용되는 방법에 대한 요약이 끝났습니다. 틀린 부분이 있으면 지적해주세요!

저작권 안내: 이 글은 해당 블로거의 원본 글이므로 블로거의 허락 없이 복제할 수 없습니다.

위 내용은 PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되기를 바랍니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.