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" } }
$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" } }
예를 들어 특정 키를 삭제하려고 합니다.
예를 들어 문서에서 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" } }
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) } }
(5) 통계 - count()
$result=$m->where($map)->count();
이 시점에서 위의 방법은 실제로 테스트되었으며 비즈니스 요구 사항을 충족할 수 있는 mongo에서 가장 일반적으로 사용되는 방법에 대한 요약이 끝났습니다. 틀린 부분이 있으면 지적해주세요!