Mongo.class.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. namespace Think\Db\Driver;
  12. use Think\Db\Driver;
  13. /**
  14. * Mongo数据库驱动
  15. */
  16. class Mongo extends Driver {
  17. protected $_mongo = null; // MongoDb Object
  18. protected $_collection = null; // MongoCollection Object
  19. protected $_dbName = ''; // dbName
  20. protected $_collectionName = ''; // collectionName
  21. protected $_cursor = null; // MongoCursor Object
  22. protected $comparison = array('neq'=>'ne','ne'=>'ne','gt'=>'gt','egt'=>'gte','gte'=>'gte','lt'=>'lt','elt'=>'lte','lte'=>'lte','in'=>'in','not in'=>'nin','nin'=>'nin');
  23. /**
  24. * 架构函数 读取数据库配置信息
  25. * @access public
  26. * @param array $config 数据库配置数组
  27. */
  28. public function __construct($config=''){
  29. if ( !class_exists('mongoClient') ) {
  30. E(L('_NOT_SUPPORT_').':Mongo');
  31. }
  32. if(!empty($config)) {
  33. $this->config = array_merge($this->config,$config);
  34. if(empty($this->config['params'])){
  35. $this->config['params'] = array();
  36. }
  37. }
  38. }
  39. /**
  40. * 连接数据库方法
  41. * @access public
  42. */
  43. public function connect($config='',$linkNum=0) {
  44. if ( !isset($this->linkID[$linkNum]) ) {
  45. if(empty($config)) $config = $this->config;
  46. $host = 'mongodb://'.($config['username']?"{$config['username']}":'').($config['password']?":{$config['password']}@":'').$config['hostname'].($config['hostport']?":{$config['hostport']}":'').'/'.($config['database']?"{$config['database']}":'');
  47. try{
  48. $this->linkID[$linkNum] = new \mongoClient( $host,$this->config['params']);
  49. }catch (\MongoConnectionException $e){
  50. E($e->getmessage());
  51. }
  52. }
  53. return $this->linkID[$linkNum];
  54. }
  55. /**
  56. * 切换当前操作的Db和Collection
  57. * @access public
  58. * @param string $collection collection
  59. * @param string $db db
  60. * @param boolean $master 是否主服务器
  61. * @return void
  62. */
  63. public function switchCollection($collection,$db='',$master=true){
  64. // 当前没有连接 则首先进行数据库连接
  65. if ( !$this->_linkID ) $this->initConnect($master);
  66. try{
  67. if(!empty($db)) { // 传人Db则切换数据库
  68. // 当前MongoDb对象
  69. $this->_dbName = $db;
  70. $this->_mongo = $this->_linkID->selectDb($db);
  71. }
  72. // 当前MongoCollection对象
  73. if($this->config['debug']) {
  74. $this->queryStr = $this->_dbName.'.getCollection('.$collection.')';
  75. }
  76. if($this->_collectionName != $collection) {
  77. $this->queryTimes++;
  78. N('db_query',1); // 兼容代码
  79. $this->debug(true);
  80. $this->_collection = $this->_mongo->selectCollection($collection);
  81. $this->debug(false);
  82. $this->_collectionName = $collection; // 记录当前Collection名称
  83. }
  84. }catch (MongoException $e){
  85. E($e->getMessage());
  86. }
  87. }
  88. /**
  89. * 释放查询结果
  90. * @access public
  91. */
  92. public function free() {
  93. $this->_cursor = null;
  94. }
  95. /**
  96. * 执行命令
  97. * @access public
  98. * @param array $command 指令
  99. * @return array
  100. */
  101. public function command($command=array(), $options=array()) {
  102. $cache = isset($options['cache'])?$options['cache']:false;
  103. if($cache) { // 查询缓存检测
  104. $key = is_string($cache['key'])?$cache['key']:md5(serialize($command));
  105. $value = S($key,'','',$cache['type']);
  106. if(false !== $value) {
  107. return $value;
  108. }
  109. }
  110. N('db_write',1); // 兼容代码
  111. $this->executeTimes++;
  112. try{
  113. if($this->config['debug']) {
  114. $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.runCommand(';
  115. $this->queryStr .= json_encode($command);
  116. $this->queryStr .= ')';
  117. }
  118. $this->debug(true);
  119. $result = $this->_mongo->command($command);
  120. $this->debug(false);
  121. if($cache && $result['ok']) { // 查询缓存写入
  122. S($key,$result,$cache['expire'],$cache['type']);
  123. }
  124. return $result;
  125. } catch (\MongoCursorException $e) {
  126. E($e->getMessage());
  127. }
  128. }
  129. /**
  130. * 执行语句
  131. * @access public
  132. * @param string $code sql指令
  133. * @param array $args 参数
  134. * @return mixed
  135. */
  136. public function execute($code,$args=array()) {
  137. $this->executeTimes++;
  138. N('db_write',1); // 兼容代码
  139. $this->debug(true);
  140. $this->queryStr = 'execute:'.$code;
  141. $result = $this->_mongo->execute($code,$args);
  142. $this->debug(false);
  143. if($result['ok']) {
  144. return $result['retval'];
  145. }else{
  146. E($result['errmsg']);
  147. }
  148. }
  149. /**
  150. * 关闭数据库
  151. * @access public
  152. */
  153. public function close() {
  154. if($this->_linkID) {
  155. $this->_linkID->close();
  156. $this->_linkID = null;
  157. $this->_mongo = null;
  158. $this->_collection = null;
  159. $this->_cursor = null;
  160. }
  161. }
  162. /**
  163. * 数据库错误信息
  164. * @access public
  165. * @return string
  166. */
  167. public function error() {
  168. $this->error = $this->_mongo->lastError();
  169. trace($this->error,'','ERR');
  170. return $this->error;
  171. }
  172. /**
  173. * 插入记录
  174. * @access public
  175. * @param mixed $data 数据
  176. * @param array $options 参数表达式
  177. * @param boolean $replace 是否replace
  178. * @return false | integer
  179. */
  180. public function insert($data,$options=array(),$replace=false) {
  181. if(isset($options['table'])) {
  182. $this->switchCollection($options['table']);
  183. }
  184. $this->model = $options['model'];
  185. $this->executeTimes++;
  186. N('db_write',1); // 兼容代码
  187. if($this->config['debug']) {
  188. $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.insert(';
  189. $this->queryStr .= $data?json_encode($data):'{}';
  190. $this->queryStr .= ')';
  191. }
  192. try{
  193. $this->debug(true);
  194. $result = $replace? $this->_collection->save($data): $this->_collection->insert($data);
  195. $this->debug(false);
  196. if($result) {
  197. $_id = $data['_id'];
  198. if(is_object($_id)) {
  199. $_id = $_id->__toString();
  200. }
  201. $this->lastInsID = $_id;
  202. }
  203. return $result;
  204. } catch (\MongoCursorException $e) {
  205. E($e->getMessage());
  206. }
  207. }
  208. /**
  209. * 插入多条记录
  210. * @access public
  211. * @param array $dataList 数据
  212. * @param array $options 参数表达式
  213. * @return bool
  214. */
  215. public function insertAll($dataList,$options=array()) {
  216. if(isset($options['table'])) {
  217. $this->switchCollection($options['table']);
  218. }
  219. $this->model = $options['model'];
  220. $this->executeTimes++;
  221. N('db_write',1); // 兼容代码
  222. try{
  223. $this->debug(true);
  224. $result = $this->_collection->batchInsert($dataList);
  225. $this->debug(false);
  226. return $result;
  227. } catch (\MongoCursorException $e) {
  228. E($e->getMessage());
  229. }
  230. }
  231. /**
  232. * 生成下一条记录ID 用于自增非MongoId主键
  233. * @access public
  234. * @param string $pk 主键名
  235. * @return integer
  236. */
  237. public function getMongoNextId($pk) {
  238. if($this->config['debug']) {
  239. $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.find({},{'.$pk.':1}).sort({'.$pk.':-1}).limit(1)';
  240. }
  241. try{
  242. $this->debug(true);
  243. $result = $this->_collection->find(array(),array($pk=>1))->sort(array($pk=>-1))->limit(1);
  244. $this->debug(false);
  245. } catch (\MongoCursorException $e) {
  246. E($e->getMessage());
  247. }
  248. $data = $result->getNext();
  249. return isset($data[$pk])?$data[$pk]+1:1;
  250. }
  251. /**
  252. * 更新记录
  253. * @access public
  254. * @param mixed $data 数据
  255. * @param array $options 表达式
  256. * @return bool
  257. */
  258. public function update($data,$options) {
  259. if(isset($options['table'])) {
  260. $this->switchCollection($options['table']);
  261. }
  262. $this->executeTimes++;
  263. N('db_write',1); // 兼容代码
  264. $this->model = $options['model'];
  265. $query = $this->parseWhere(isset($options['where'])?$options['where']:array());
  266. $set = $this->parseSet($data);
  267. if($this->config['debug']) {
  268. $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.update(';
  269. $this->queryStr .= $query?json_encode($query):'{}';
  270. $this->queryStr .= ','.json_encode($set).')';
  271. }
  272. try{
  273. $this->debug(true);
  274. if(isset($options['limit']) && $options['limit'] == 1) {
  275. $multiple = array("multiple" => false);
  276. }else{
  277. $multiple = array("multiple" => true);
  278. }
  279. $result = $this->_collection->update($query,$set,$multiple);
  280. $this->debug(false);
  281. return $result;
  282. } catch (\MongoCursorException $e) {
  283. E($e->getMessage());
  284. }
  285. }
  286. /**
  287. * 删除记录
  288. * @access public
  289. * @param array $options 表达式
  290. * @return false | integer
  291. */
  292. public function delete($options=array()) {
  293. if(isset($options['table'])) {
  294. $this->switchCollection($options['table']);
  295. }
  296. $query = $this->parseWhere(isset($options['where'])?$options['where']:array());
  297. $this->model = $options['model'];
  298. $this->executeTimes++;
  299. N('db_write',1); // 兼容代码
  300. if($this->config['debug']) {
  301. $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.remove('.json_encode($query).')';
  302. }
  303. try{
  304. $this->debug(true);
  305. $result = $this->_collection->remove($query);
  306. $this->debug(false);
  307. return $result;
  308. } catch (\MongoCursorException $e) {
  309. E($e->getMessage());
  310. }
  311. }
  312. /**
  313. * 清空记录
  314. * @access public
  315. * @param array $options 表达式
  316. * @return false | integer
  317. */
  318. public function clear($options=array()){
  319. if(isset($options['table'])) {
  320. $this->switchCollection($options['table']);
  321. }
  322. $this->model = $options['model'];
  323. $this->executeTimes++;
  324. N('db_write',1); // 兼容代码
  325. if($this->config['debug']) {
  326. $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.remove({})';
  327. }
  328. try{
  329. $this->debug(true);
  330. $result = $this->_collection->drop();
  331. $this->debug(false);
  332. return $result;
  333. } catch (\MongoCursorException $e) {
  334. E($e->getMessage());
  335. }
  336. }
  337. /**
  338. * 查找记录
  339. * @access public
  340. * @param array $options 表达式
  341. * @return iterator
  342. */
  343. public function select($options=array()) {
  344. if(isset($options['table'])) {
  345. $this->switchCollection($options['table'],'',false);
  346. }
  347. $this->model = $options['model'];
  348. $this->queryTimes++;
  349. N('db_query',1); // 兼容代码
  350. $query = $this->parseWhere(isset($options['where'])?$options['where']:array());
  351. $field = $this->parseField(isset($options['field'])?$options['field']:array());
  352. try{
  353. if($this->config['debug']) {
  354. $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.find(';
  355. $this->queryStr .= $query? json_encode($query):'{}';
  356. if(is_array($field) && count($field)) {
  357. foreach ($field as $f=>$v)
  358. $_field_array[$f] = $v ? 1 : 0;
  359. $this->queryStr .= $field? ', '.json_encode($_field_array):', {}';
  360. }
  361. $this->queryStr .= ')';
  362. }
  363. $this->debug(true);
  364. $_cursor = $this->_collection->find($query,$field);
  365. if(!empty($options['order'])) {
  366. $order = $this->parseOrder($options['order']);
  367. if($this->config['debug']) {
  368. $this->queryStr .= '.sort('.json_encode($order).')';
  369. }
  370. $_cursor = $_cursor->sort($order);
  371. }
  372. if(isset($options['page'])) { // 根据页数计算limit
  373. list($page,$length) = $options['page'];
  374. $page = $page>0 ? $page : 1;
  375. $length = $length>0 ? $length : (is_numeric($options['limit'])?$options['limit']:20);
  376. $offset = $length*((int)$page-1);
  377. $options['limit'] = $offset.','.$length;
  378. }
  379. if(isset($options['limit'])) {
  380. list($offset,$length) = $this->parseLimit($options['limit']);
  381. if(!empty($offset)) {
  382. if($this->config['debug']) {
  383. $this->queryStr .= '.skip('.intval($offset).')';
  384. }
  385. $_cursor = $_cursor->skip(intval($offset));
  386. }
  387. if($this->config['debug']) {
  388. $this->queryStr .= '.limit('.intval($length).')';
  389. }
  390. $_cursor = $_cursor->limit(intval($length));
  391. }
  392. $this->debug(false);
  393. $this->_cursor = $_cursor;
  394. $resultSet = iterator_to_array($_cursor);
  395. return $resultSet;
  396. } catch (\MongoCursorException $e) {
  397. E($e->getMessage());
  398. }
  399. }
  400. /**
  401. * 查找某个记录
  402. * @access public
  403. * @param array $options 表达式
  404. * @return array
  405. */
  406. public function find($options=array()){
  407. $options['limit'] = 1;
  408. $find = $this->select($options);
  409. return array_shift($find);
  410. }
  411. /**
  412. * 统计记录数
  413. * @access public
  414. * @param array $options 表达式
  415. * @return iterator
  416. */
  417. public function count($options=array()){
  418. if(isset($options['table'])) {
  419. $this->switchCollection($options['table'],'',false);
  420. }
  421. $this->model = $options['model'];
  422. $this->queryTimes++;
  423. N('db_query',1); // 兼容代码
  424. $query = $this->parseWhere(isset($options['where'])?$options['where']:array());
  425. if($this->config['debug']) {
  426. $this->queryStr = $this->_dbName.'.'.$this->_collectionName;
  427. $this->queryStr .= $query?'.find('.json_encode($query).')':'';
  428. $this->queryStr .= '.count()';
  429. }
  430. try{
  431. $this->debug(true);
  432. $count = $this->_collection->count($query);
  433. $this->debug(false);
  434. return $count;
  435. } catch (\MongoCursorException $e) {
  436. E($e->getMessage());
  437. }
  438. }
  439. public function group($keys,$initial,$reduce,$options=array()){
  440. if(isset($options['table']) && $this->_collectionName != $options['table']) {
  441. $this->switchCollection($options['table'],'',false);
  442. }
  443. $cache = isset($options['cache'])?$options['cache']:false;
  444. if($cache) {
  445. $key = is_string($cache['key'])?$cache['key']:md5(serialize($options));
  446. $value = S($key,'','',$cache['type']);
  447. if(false !== $value) {
  448. return $value;
  449. }
  450. }
  451. $this->model = $options['model'];
  452. $this->queryTimes++;
  453. N('db_query',1); // 兼容代码
  454. $query = $this->parseWhere(isset($options['where'])?$options['where']:array());
  455. if($this->config['debug']) {
  456. $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.group({key:'.json_encode($keys).',cond:'.
  457. json_encode($options['condition']) . ',reduce:' .
  458. json_encode($reduce).',initial:'.
  459. json_encode($initial).'})';
  460. }
  461. try{
  462. $this->debug(true);
  463. $option = array('condition'=>$options['condition'], 'finalize'=>$options['finalize'], 'maxTimeMS'=>$options['maxTimeMS']);
  464. $group = $this->_collection->group($keys,$initial,$reduce,$options);
  465. $this->debug(false);
  466. if($cache && $group['ok'])
  467. S($key,$group,$cache['expire'],$cache['type']);
  468. return $group;
  469. } catch (\MongoCursorException $e) {
  470. E($e->getMessage());
  471. }
  472. }
  473. /**
  474. * 取得数据表的字段信息
  475. * @access public
  476. * @return array
  477. */
  478. public function getFields($collection=''){
  479. if(!empty($collection) && $collection != $this->_collectionName) {
  480. $this->switchCollection($collection,'',false);
  481. }
  482. $this->queryTimes++;
  483. N('db_query',1); // 兼容代码
  484. if($this->config['debug']) {
  485. $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.findOne()';
  486. }
  487. try{
  488. $this->debug(true);
  489. $result = $this->_collection->findOne();
  490. $this->debug(false);
  491. } catch (\MongoCursorException $e) {
  492. E($e->getMessage());
  493. }
  494. if($result) { // 存在数据则分析字段
  495. $info = array();
  496. foreach ($result as $key=>$val){
  497. $info[$key] = array(
  498. 'name' => $key,
  499. 'type' => getType($val),
  500. );
  501. }
  502. return $info;
  503. }
  504. // 暂时没有数据 返回false
  505. return false;
  506. }
  507. /**
  508. * 取得当前数据库的collection信息
  509. * @access public
  510. */
  511. public function getTables(){
  512. if($this->config['debug']) {
  513. $this->queryStr = $this->_dbName.'.getCollenctionNames()';
  514. }
  515. $this->queryTimes++;
  516. N('db_query',1); // 兼容代码
  517. $this->debug(true);
  518. $list = $this->_mongo->listCollections();
  519. $this->debug(false);
  520. $info = array();
  521. foreach ($list as $collection){
  522. $info[] = $collection->getName();
  523. }
  524. return $info;
  525. }
  526. /**
  527. * 取得当前数据库的对象
  528. * @access public
  529. * @return object mongoClient
  530. */
  531. public function getDB(){
  532. return $this->_mongo;
  533. }
  534. /**
  535. * 取得当前集合的对象
  536. * @access public
  537. * @return object MongoCollection
  538. */
  539. public function getCollection(){
  540. return $this->_collection;
  541. }
  542. /**
  543. * set分析
  544. * @access protected
  545. * @param array $data
  546. * @return string
  547. */
  548. protected function parseSet($data) {
  549. $result = array();
  550. foreach ($data as $key=>$val){
  551. if(is_array($val)) {
  552. switch($val[0]) {
  553. case 'inc':
  554. $result['$inc'][$key] = (int)$val[1];
  555. break;
  556. case 'set':
  557. case 'unset':
  558. case 'push':
  559. case 'pushall':
  560. case 'addtoset':
  561. case 'pop':
  562. case 'pull':
  563. case 'pullall':
  564. $result['$'.$val[0]][$key] = $val[1];
  565. break;
  566. default:
  567. $result['$set'][$key] = $val;
  568. }
  569. }else{
  570. $result['$set'][$key] = $val;
  571. }
  572. }
  573. return $result;
  574. }
  575. /**
  576. * order分析
  577. * @access protected
  578. * @param mixed $order
  579. * @return array
  580. */
  581. protected function parseOrder($order) {
  582. if(is_string($order)) {
  583. $array = explode(',',$order);
  584. $order = array();
  585. foreach ($array as $key=>$val){
  586. $arr = explode(' ',trim($val));
  587. if(isset($arr[1])) {
  588. $arr[1] = $arr[1]=='asc'?1:-1;
  589. }else{
  590. $arr[1] = 1;
  591. }
  592. $order[$arr[0]] = $arr[1];
  593. }
  594. }
  595. return $order;
  596. }
  597. /**
  598. * limit分析
  599. * @access protected
  600. * @param mixed $limit
  601. * @return array
  602. */
  603. protected function parseLimit($limit) {
  604. if(strpos($limit,',')) {
  605. $array = explode(',',$limit);
  606. }else{
  607. $array = array(0,$limit);
  608. }
  609. return $array;
  610. }
  611. /**
  612. * field分析
  613. * @access protected
  614. * @param mixed $fields
  615. * @return array
  616. */
  617. public function parseField($fields){
  618. if(empty($fields)) {
  619. $fields = array();
  620. }
  621. if(is_string($fields)) {
  622. $_fields = explode(',',$fields);
  623. $fields = array();
  624. foreach ($_fields as $f)
  625. $fields[$f] = true;
  626. }elseif(is_array($fields)) {
  627. $_fields = $fields;
  628. $fields = array();
  629. foreach ($_fields as $f=>$v) {
  630. if(is_numeric($f))
  631. $fields[$v] = true;
  632. else
  633. $fields[$f] = $v ? true : false;
  634. }
  635. }
  636. return $fields;
  637. }
  638. /**
  639. * where分析
  640. * @access protected
  641. * @param mixed $where
  642. * @return array
  643. */
  644. public function parseWhere($where){
  645. $query = array();
  646. $return = array();
  647. $_logic = '$and';
  648. if(isset($where['_logic'])){
  649. $where['_logic'] = strtolower($where['_logic']);
  650. $_logic = in_array($where['_logic'], array('or','xor','nor', 'and'))?'$'.$where['_logic']:$_logic;
  651. unset($where['_logic']);
  652. }
  653. foreach ($where as $key=>$val){
  654. if('_id' != $key && 0===strpos($key,'_')) {
  655. // 解析特殊条件表达式
  656. $parse = $this->parseThinkWhere($key,$val);
  657. $query = array_merge($query,$parse);
  658. }else{
  659. // 查询字段的安全过滤
  660. if(!preg_match('/^[A-Z_\|\&\-.a-z0-9]+$/',trim($key))){
  661. E(L('_ERROR_QUERY_').':'.$key);
  662. }
  663. $key = trim($key);
  664. if(strpos($key,'|')) {
  665. $array = explode('|',$key);
  666. $str = array();
  667. foreach ($array as $k){
  668. $str[] = $this->parseWhereItem($k,$val);
  669. }
  670. $query['$or'] = $str;
  671. }elseif(strpos($key,'&')){
  672. $array = explode('&',$key);
  673. $str = array();
  674. foreach ($array as $k){
  675. $str[] = $this->parseWhereItem($k,$val);
  676. }
  677. $query = array_merge($query,$str);
  678. }else{
  679. $str = $this->parseWhereItem($key,$val);
  680. $query = array_merge($query,$str);
  681. }
  682. }
  683. }
  684. if($_logic == '$and')
  685. return $query;
  686. foreach($query as $key=>$val)
  687. $return[$_logic][] = array($key=>$val);
  688. return $return;
  689. }
  690. /**
  691. * 特殊条件分析
  692. * @access protected
  693. * @param string $key
  694. * @param mixed $val
  695. * @return string
  696. */
  697. protected function parseThinkWhere($key,$val) {
  698. $query = array();
  699. switch($key) {
  700. case '_query': // 字符串模式查询条件
  701. parse_str($val,$query);
  702. if(isset($query['_logic']) && strtolower($query['_logic']) == 'or' ) {
  703. unset($query['_logic']);
  704. $query['$or'] = $query;
  705. }
  706. break;
  707. case '_complex': // 子查询模式查询条件
  708. $__logic = strtolower($val['_logic']);
  709. if(isset($val['_logic']) && in_array($__logic, $_logic) ) {
  710. unset($val['_logic']);
  711. $query['$'.$__logic] = $val;
  712. }
  713. break;
  714. case '_string':// MongoCode查询
  715. $query['$where'] = new \MongoCode($val);
  716. break;
  717. }
  718. //兼容 MongoClient OR条件查询方法
  719. if(isset($query['$or']) && !is_array(current($query['$or']))) {
  720. $val = array();
  721. foreach ($query['$or'] as $k=>$v)
  722. $val[] = array($k=>$v);
  723. $query['$or'] = $val;
  724. }
  725. return $query;
  726. }
  727. /**
  728. * where子单元分析
  729. * @access protected
  730. * @param string $key
  731. * @param mixed $val
  732. * @return array
  733. */
  734. protected function parseWhereItem($key,$val) {
  735. $query = array();
  736. if(is_array($val)) {
  737. if(is_string($val[0])) {
  738. $con = strtolower($val[0]);
  739. if(in_array($con,array('neq','ne','gt','egt','gte','lt','lte','elt'))) { // 比较运算
  740. $k = '$'.$this->comparison[$con];
  741. $query[$key] = array($k=>$val[1]);
  742. }elseif('like'== $con){ // 模糊查询 采用正则方式
  743. $query[$key] = new \MongoRegex("/".$val[1]."/");
  744. }elseif('mod'==$con){ // mod 查询
  745. $query[$key] = array('$mod'=>$val[1]);
  746. }elseif('regex'==$con){ // 正则查询
  747. $query[$key] = new \MongoRegex($val[1]);
  748. }elseif(in_array($con,array('in','nin','not in'))){ // IN NIN 运算
  749. $data = is_string($val[1])? explode(',',$val[1]):$val[1];
  750. $k = '$'.$this->comparison[$con];
  751. $query[$key] = array($k=>$data);
  752. }elseif('all'==$con){ // 满足所有指定条件
  753. $data = is_string($val[1])? explode(',',$val[1]):$val[1];
  754. $query[$key] = array('$all'=>$data);
  755. }elseif('between'==$con){ // BETWEEN运算
  756. $data = is_string($val[1])? explode(',',$val[1]):$val[1];
  757. $query[$key] = array('$gte'=>$data[0],'$lte'=>$data[1]);
  758. }elseif('not between'==$con){
  759. $data = is_string($val[1])? explode(',',$val[1]):$val[1];
  760. $query[$key] = array('$lt'=>$data[0],'$gt'=>$data[1]);
  761. }elseif('exp'==$con){ // 表达式查询
  762. $query['$where'] = new \MongoCode($val[1]);
  763. }elseif('exists'==$con){ // 字段是否存在
  764. $query[$key] = array('$exists'=>(bool)$val[1]);
  765. }elseif('size'==$con){ // 限制属性大小
  766. $query[$key] = array('$size'=>intval($val[1]));
  767. }elseif('type'==$con){ // 限制字段类型 1 浮点型 2 字符型 3 对象或者MongoDBRef 5 MongoBinData 7 MongoId 8 布尔型 9 MongoDate 10 NULL 15 MongoCode 16 32位整型 17 MongoTimestamp 18 MongoInt64 如果是数组的话判断元素的类型
  768. $query[$key] = array('$type'=>intval($val[1]));
  769. }else{
  770. $query[$key] = $val;
  771. }
  772. return $query;
  773. }
  774. }
  775. $query[$key] = $val;
  776. return $query;
  777. }
  778. }