Mongo_db.php 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. <?php if (!defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * Class MongoDB操作类
  4. */
  5. Class Mongo_db
  6. {
  7. private $CI;
  8. private $config = array();
  9. private $manager;
  10. private $param;
  11. private $db;
  12. private $hostname;
  13. private $port;
  14. private $database;
  15. private $username;
  16. private $password;
  17. private $debug;
  18. private $filter = array();
  19. private $option = array();
  20. private $selects = array();
  21. private $updates = array();
  22. private $pipeline = array();
  23. private $limit = 999999;
  24. private $offset = 0;
  25. private $db_version;
  26. /**
  27. * --------------------------------------------------------------------------------
  28. * Class Constructor
  29. * --------------------------------------------------------------------------------
  30. *
  31. * Automatically check if the Mongo PECL extension has been installed/enabled.
  32. * Get Access to all CodeIgniter available resources.
  33. * Load mongodb config file from application/config folder.
  34. * Prepare the connection variables and establish a connection to the MongoDB.
  35. * Try to connect on MongoDB server.
  36. */
  37. function __construct($param)
  38. {
  39. if (!class_exists('MongoDB\Driver\Manager') && !class_exists('MongoDB\Driver\Command')) {
  40. show_error("The MongoDB Driver extension has not been installed or enabled", 500);
  41. }
  42. $this->CI =& get_instance();
  43. $this->CI->load->config('mongo_db');
  44. $this->config = $this->CI->config->item('mongo_db');
  45. $this->param = $param;
  46. $this->connect();
  47. }
  48. /*
  49. * --------------------------------------------------------------------------------
  50. * Prepare configuration for mongoDB connection
  51. * --------------------------------------------------------------------------------
  52. *
  53. * Validate group name or autoload default group name from config file.
  54. * Validate all the properties present in config file of the group.
  55. */
  56. private function prepare()
  57. {
  58. if (is_array($this->param) && count($this->param) > 0 && isset($this->param['activate']) == TRUE) {
  59. $this->activate = $this->param['activate'];
  60. } else if (isset($this->config['active']) && !empty($this->config['active'])) {
  61. $this->activate = $this->config['active'];
  62. } else {
  63. show_error("MongoDB configuration is missing.", 500);
  64. }
  65. if (isset($this->config[$this->activate]) == TRUE) {
  66. if (empty($this->config[$this->activate]['hostname'])) {
  67. show_error("Hostname missing from mongodb config group : {$this->activate}", 500);
  68. } else {
  69. $this->hostname = trim($this->config[$this->activate]['hostname']);
  70. }
  71. if (empty($this->config[$this->activate]['port'])) {
  72. show_error("Port number missing from mongodb config group : {$this->activate}", 500);
  73. } else {
  74. $this->port = trim($this->config[$this->activate]['port']);
  75. }
  76. if($this->config[$this->activate]['no_auth'] == FALSE){
  77. if (empty($this->config[$this->activate]['username'])) {
  78. show_error("Username missing from mongodb config group : {$this->activate}", 500);
  79. } else {
  80. $this->username = trim($this->config[$this->activate]['username']);
  81. }
  82. if (empty($this->config[$this->activate]['password'])) {
  83. show_error("Password missing from mongodb config group : {$this->activate}", 500);
  84. } else {
  85. $this->password = trim($this->config[$this->activate]['password']);
  86. }
  87. }
  88. if (empty($this->config[$this->activate]['database'])) {
  89. show_error("Database name missing from mongodb config group : {$this->activate}", 500);
  90. } else {
  91. $this->database = trim($this->config[$this->activate]['database']);
  92. }
  93. if (empty($this->config[$this->activate]['db_debug'])) {
  94. $this->debug = FALSE;
  95. } else {
  96. $this->debug = $this->config[$this->activate]['db_debug'];
  97. }
  98. } else {
  99. show_error("mongodb config group : <strong>{$this->activate}</strong> does not exist.", 500);
  100. }
  101. }
  102. /**
  103. * --------------------------------------------------------------------------------
  104. * Connect to MongoDB Database
  105. * --------------------------------------------------------------------------------
  106. *
  107. * Connect to mongoDB database or throw exception with the error message.
  108. */
  109. private function connect()
  110. {
  111. $this->prepare();
  112. try {
  113. $dns = "mongodb://{$this->hostname}:{$this->port}";
  114. if (isset($this->config[$this->activate]['no_auth']) == TRUE && $this->config[$this->activate]['no_auth'] == TRUE) {
  115. $options = array();
  116. } else {
  117. $options = array('username' => $this->username, 'password' => $this->password);
  118. }
  119. $this->manager = new MongoDB\Driver\Manager($dns, $options);
  120. $this->db = $this->database;
  121. $this->db_version = $this->get_db_version();
  122. } catch (Exception $e) {
  123. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  124. show_error("Unable to connect to MongoDB: {$e->getMessage()}", 500);
  125. } else {
  126. show_error("Unable to connect to MongoDB", 500);
  127. }
  128. }
  129. }
  130. public function get_manager(){
  131. return $this->manager;
  132. }
  133. public function get_db_version(){
  134. $command = new MongoDB\Driver\Command(array("buildinfo" => 1));
  135. try {
  136. $cursor = $this->manager->executeCommand("admin", $command);
  137. $buildinfo = (array)$cursor->toArray()[0];
  138. if(array_key_exists("version",$buildinfo)){
  139. return $buildinfo['version'];
  140. }else{
  141. return "";
  142. }
  143. }catch (Exception $e) {
  144. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  145. show_error("MongoDB query failed: {$e->getMessage()}", 500);
  146. } else {
  147. Throw new Exception("查询数据发生异常!");
  148. }
  149. }
  150. }
  151. /**
  152. * 查询数据
  153. * @param $tales
  154. */
  155. public function get($table)
  156. {
  157. if (empty($table)) {
  158. show_error("In order to retrieve documents from MongoDB, a collection name must be passed", 500);
  159. }
  160. try {
  161. if (is_array($this->selects) && count($this->selects) > 0) {
  162. $this->option['projection'] = $this->selects;
  163. }
  164. $query = new MongoDB\Driver\Query($this->filter, $this->option);
  165. $table = $this->database . '.' . $table;
  166. $data = $this->manager->executeQuery($table, $query);
  167. $this->_clear();
  168. $returns = [];
  169. foreach ($data as $doc) {
  170. $returns[] = $this->object_array($doc);
  171. }
  172. return $returns;
  173. } catch (Exception $e) {
  174. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  175. show_error("MongoDB query failed: {$e->getMessage()}", 500);
  176. } else {
  177. Throw new Exception("查询数据发生异常!");
  178. }
  179. }
  180. }
  181. /**
  182. * 根据条件查询
  183. * @param string $table
  184. * @param array $filter
  185. * @return mixed
  186. */
  187. public function get_where($table = "", $filter = array())
  188. {
  189. if (is_array($filter) && count($filter) > 0) {
  190. return $this->where($filter)->get($table);
  191. } else {
  192. show_error("Nothing passed to perform search or value is empty.", 500);
  193. }
  194. }
  195. public function select($includes = array(), $excludes = array())
  196. {
  197. if (!is_array($includes)) {
  198. $includes = array();
  199. }
  200. if (!is_array($excludes)) {
  201. $excludes = array();
  202. }
  203. if (!empty($includes)) {
  204. foreach ($includes as $key => $col) {
  205. $this->selects[$col] = 1;
  206. }
  207. }
  208. if (!empty($excludes)) {
  209. foreach ($excludes as $col) {
  210. $this->selects[$col] = 0;
  211. }
  212. }
  213. return ($this);
  214. }
  215. public function where($filter, $value = null)
  216. {
  217. if (is_array($filter)) {
  218. foreach ($filter as $wh => $val) {
  219. $this->filter[$wh] = $val;
  220. }
  221. } elseif($filter) {
  222. $this->filter[$filter] = $value;
  223. }
  224. return $this;
  225. }
  226. public function where_or($filter = array())
  227. {
  228. if (is_array($filter) && count($filter) > 0) {
  229. if (!isset($this->filter['$or']) || !is_array($this->filter['$or'])) {
  230. $this->filter['$or'] = array();
  231. }
  232. foreach ($filter as $wh => $val) {
  233. $this->filter['$or'][] = array($wh => $val);
  234. }
  235. return ($this);
  236. } else {
  237. show_error("Where value should be an array.", 500);
  238. }
  239. }
  240. public function where_in($field = "", $in = array())
  241. {
  242. if (empty($field)) {
  243. show_error("Mongo field is require to perform where in query.", 500);
  244. }
  245. if (is_array($in) && count($in) > 0) {
  246. $this->_w($field);
  247. $this->filter[$field]['$in'] = $in;
  248. return ($this);
  249. } else {
  250. show_error("in value should be an array.", 500);
  251. }
  252. }
  253. public function where_in_all($field = "", $in = array())
  254. {
  255. if (empty($field)) {
  256. show_error("Mongo field is require to perform where all in query.", 500);
  257. }
  258. if (is_array($in) && count($in) > 0) {
  259. $this->_w($field);
  260. $this->filter[$field]['$all'] = $in;
  261. return ($this);
  262. } else {
  263. show_error("in value should be an array.", 500);
  264. }
  265. }
  266. public function where_not_in($field = "", $in = array())
  267. {
  268. if (empty($field)) {
  269. show_error("Mongo field is require to perform where not in query.", 500);
  270. }
  271. if (is_array($in) && count($in) > 0) {
  272. $this->_w($field);
  273. $this->filter[$field]['$nin'] = $in;
  274. return ($this);
  275. } else {
  276. show_error("in value should be an array.", 500);
  277. }
  278. }
  279. public function where_gt($field = "", $x)
  280. {
  281. if (!isset($field)) {
  282. show_error("Mongo field is require to perform greater then query.", 500);
  283. }
  284. if (!isset($x)) {
  285. show_error("Mongo field's value is require to perform greater then query.", 500);
  286. }
  287. $this->_w($field);
  288. $this->filter[$field]['$gt'] = $x;
  289. return ($this);
  290. }
  291. /**
  292. * --------------------------------------------------------------------------------
  293. * Where less than
  294. * --------------------------------------------------------------------------------
  295. *
  296. * Get the documents where the value of a $field is less than $x
  297. *
  298. * @usage : $this->mongo_db->where_lt('foo', 20);
  299. */
  300. public function where_lt($field = "", $x)
  301. {
  302. if (!isset($field)) {
  303. show_error("Mongo field is require to perform less then query.", 500);
  304. }
  305. if (!isset($x)) {
  306. show_error("Mongo field's value is require to perform less then query.", 500);
  307. }
  308. $this->_w($field);
  309. $this->filter[$field]['$lt'] = $x;
  310. return ($this);
  311. }
  312. /**
  313. * --------------------------------------------------------------------------------
  314. * Where less than or equal to
  315. * --------------------------------------------------------------------------------
  316. *
  317. * Get the documents where the value of a $field is less than or equal to $x
  318. *
  319. * @usage : $this->mongo_db->where_lte('foo', 20);
  320. */
  321. public function where_lte($field = "", $x)
  322. {
  323. if (!isset($field)) {
  324. show_error("Mongo field is require to perform less then or equal to query.", 500);
  325. }
  326. if (!isset($x)) {
  327. show_error("Mongo field's value is require to perform less then or equal to query.", 500);
  328. }
  329. $this->_w($field);
  330. $this->filter[$field]['$lte'] = $x;
  331. return ($this);
  332. }
  333. /**
  334. * --------------------------------------------------------------------------------
  335. * Where between
  336. * --------------------------------------------------------------------------------
  337. *
  338. * Get the documents where the value of a $field is between $x and $y
  339. *
  340. * @usage : $this->mongo_db->where_between('foo', 20, 30);
  341. */
  342. public function where_between($field = "", $x, $y)
  343. {
  344. if (!isset($field)) {
  345. show_error("Mongo field is require to perform greater then or equal to query.", 500);
  346. }
  347. if (!isset($x)) {
  348. show_error("Mongo field's start value is require to perform greater then or equal to query.", 500);
  349. }
  350. if (!isset($y)) {
  351. show_error("Mongo field's end value is require to perform greater then or equal to query.", 500);
  352. }
  353. $this->_w($field);
  354. $this->filter[$field]['$gte'] = $x;
  355. $this->filter[$field]['$lte'] = $y;
  356. return ($this);
  357. }
  358. /**
  359. * --------------------------------------------------------------------------------
  360. * Where between and but not equal to
  361. * --------------------------------------------------------------------------------
  362. *
  363. * Get the documents where the value of a $field is between but not equal to $x and $y
  364. *
  365. * @usage : $this->mongo_db->where_between_ne('foo', 20, 30);
  366. */
  367. public function where_between_ne($field = "", $x, $y)
  368. {
  369. if (!isset($field)) {
  370. show_error("Mongo field is require to perform between and but not equal to query.", 500);
  371. }
  372. if (!isset($x)) {
  373. show_error("Mongo field's start value is require to perform between and but not equal to query.", 500);
  374. }
  375. if (!isset($y)) {
  376. show_error("Mongo field's end value is require to perform between and but not equal to query.", 500);
  377. }
  378. $this->_w($field);
  379. $this->filter[$field]['$gt'] = $x;
  380. $this->filter[$field]['$lt'] = $y;
  381. return ($this);
  382. }
  383. /**
  384. * --------------------------------------------------------------------------------
  385. * Where not equal
  386. * --------------------------------------------------------------------------------
  387. *
  388. * Get the documents where the value of a $field is not equal to $x
  389. *
  390. * @usage : $this->mongo_db->where_ne('foo', 1)->get('foobar');
  391. */
  392. public function where_ne($field = '', $x)
  393. {
  394. if (!isset($field)) {
  395. show_error("Mongo field is require to perform Where not equal to query.", 500);
  396. }
  397. if (!isset($x)) {
  398. show_error("Mongo field's value is require to perform Where not equal to query.", 500);
  399. }
  400. $this->_w($field);
  401. $this->filter[$field]['$ne'] = $x;
  402. return ($this);
  403. }
  404. /**
  405. * --------------------------------------------------------------------------------
  406. * Like
  407. * --------------------------------------------------------------------------------
  408. *
  409. * Get the documents where the (string) value of a $field is like a value. The defaults
  410. * allow for a case-insensitive search.
  411. *
  412. * @param $flags
  413. * Allows for the typical regular expression flags:
  414. * i = case insensitive
  415. * m = multiline
  416. * x = can contain comments
  417. * l = locale
  418. * s = dotall, "." matches everything, including newlines
  419. * u = match unicode
  420. *
  421. * @param $enable_start_wildcard
  422. * If set to anything other than TRUE, a starting line character "^" will be prepended
  423. * to the search value, representing only searching for a value at the start of
  424. * a new line.
  425. *
  426. * @param $enable_end_wildcard
  427. * If set to anything other than TRUE, an ending line character "$" will be appended
  428. * to the search value, representing only searching for a value at the end of
  429. * a line.
  430. *
  431. * @usage : $this->mongo_db->like('foo', 'bar', 'im', FALSE, TRUE);
  432. */
  433. public function like($field = "", $value = "", $flags = "i")
  434. {
  435. if (empty($field)) {
  436. show_error("Mongo field is require to perform like query.", 500);
  437. }
  438. if (empty($value)) {
  439. show_error("Mongo field's value is require to like query.", 500);
  440. }
  441. $field = (string)trim($field);
  442. $this->_w($field);
  443. $value = (string)trim($value);
  444. $this->filter[$field] = $this->get_regex($value, $flags);
  445. return ($this);
  446. }
  447. public function create_like($value = "", $flags = "i")
  448. {
  449. if (empty($value)) {
  450. show_error("Mongo field's value is require to like query.", 500);
  451. }
  452. $value = (string)trim($value);
  453. return $this->get_regex($value, $flags);
  454. }
  455. /**
  456. * --------------------------------------------------------------------------------
  457. * Count
  458. * --------------------------------------------------------------------------------
  459. *
  460. * Count the documents based upon the passed parameters
  461. *
  462. * @usage : $this->mongo_db->count('foo');
  463. */
  464. public function count($collection = "")
  465. {
  466. if (empty($collection)) {
  467. show_error("In order to retrieve a count of documents from MongoDB, a collection name must be passed", 500);
  468. }
  469. $count = $this->query_count($collection, $this->filter);
  470. $this->_clear();
  471. return ($count);
  472. }
  473. public function order_by($fields = array())
  474. {
  475. if(is_array($fields)) {
  476. foreach ($fields as $col => $val) {
  477. if ($val == -1 || $val === FALSE || strtolower($val) == 'desc') {
  478. $this->option['sort'][$col] = -1;
  479. } else {
  480. $this->option['sort'][$col] = 1;
  481. }
  482. }
  483. }
  484. return ($this);
  485. }
  486. public function limit($x = 99999)
  487. {
  488. if ($x !== NULL && is_numeric($x) && $x >= 1) {
  489. $this->option['limit'] = (int)$x;
  490. }
  491. return ($this);
  492. }
  493. public function offset($x = 0)
  494. {
  495. if ($x !== NULL && is_numeric($x) && $x >= 1) {
  496. $this->option['skip'] = (int)$x;
  497. }
  498. return ($this);
  499. }
  500. public function set_wheres($wheres)
  501. {
  502. if (is_array($wheres) && count($wheres) > 0) {
  503. $this->filter = $wheres;
  504. }
  505. return ($this);
  506. }
  507. public function set($fields, $value = NULL)
  508. {
  509. if (is_string($fields)) {
  510. $this->updates['$set'][$fields] = $value;
  511. } elseif (is_array($fields)) {
  512. foreach ($fields as $field => $value) {
  513. $this->updates['$set'][$field] = $value;
  514. }
  515. }
  516. return $this;
  517. }
  518. public function update_all($table, $option = [])
  519. {
  520. try {
  521. $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]);
  522. $this->option = array('multi' => true);
  523. $bulk->update($this->filter, $this->updates, $this->option);
  524. $table = $this->database . '.' . $table;
  525. $ret = $this->manager->executeBulkWrite($table, $bulk);
  526. $this->_clear();
  527. return $ret;
  528. } catch (Exception $e) {
  529. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  530. show_error('table: ' . $table . '. pipeline: ' . json_encode($this->filter) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine());
  531. } else {
  532. Throw new Exception("更新数据发生异常!");
  533. }
  534. }
  535. }
  536. /**
  537. * --------------------------------------------------------------------------------
  538. * _clear
  539. * --------------------------------------------------------------------------------
  540. *
  541. * Resets the class variables to default settings
  542. */
  543. private function _clear()
  544. {
  545. $this->filter = array();
  546. $this->option = array();
  547. $this->pipeline = array();
  548. $this->selects = array();
  549. $this->limit = 999999;
  550. $this->offset = 0;
  551. }
  552. /**
  553. * --------------------------------------------------------------------------------
  554. * Where initializer
  555. * --------------------------------------------------------------------------------
  556. *
  557. * Prepares parameters for insertion in $wheres array().
  558. */
  559. private function _w($param)
  560. {
  561. if (!isset($this->filter[$param])) {
  562. $this->filter[$param] = array();
  563. }
  564. }
  565. /**
  566. * 获取MongoDB ObjectID
  567. * @param $_id
  568. * @return \MongoDB\BSON\objectID
  569. */
  570. public function get_mongo_id($_id)
  571. {
  572. if (is_string($_id)) {
  573. try {
  574. $_id = new MongoDB\BSON\objectID($_id);
  575. } catch (Exception $e) {
  576. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  577. show_error('get_mongo_id:' . $_id . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine());
  578. } else {
  579. Throw new Exception("获取MongoDB ObjectID 发生异常!");
  580. }
  581. }
  582. }
  583. return $_id;
  584. }
  585. /**
  586. * ָ插入一或多条数据
  587. * @param string $table 数据库表单名称
  588. * @param array $data 需要插入的数据
  589. * @param bool $is_multi 是否批处理
  590. * @return bool ִ执行结果
  591. * @throws Exception
  592. */
  593. public function insert($table, $data, $is_multi = FALSE)
  594. {
  595. try {
  596. $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]);
  597. if (!$is_multi) {
  598. $bulk->insert($data);
  599. } else {
  600. foreach ($data as $one_data) {
  601. $bulk->insert($one_data);
  602. }
  603. }
  604. $table = $this->database . '.' . $table;
  605. return $this->manager->executeBulkWrite($table, $bulk);
  606. } catch (Exception $e) {
  607. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  608. show_error('table: ' . $table . '. data: ' . json_encode($data) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine());
  609. } else {
  610. Throw new Exception("插入数据发生异常!");
  611. }
  612. }
  613. }
  614. /**
  615. * 获取单条数据库数据
  616. * @param string $table 数据库表单名称
  617. * @param array $filter 过滤条件
  618. * @param array $option 列、排序、分页等
  619. * @return objects 符合条件数据
  620. * @throws Exception
  621. */
  622. public function find_one($table)
  623. {
  624. if (empty($table)) {
  625. show_error("In order to retrieve documents from MongoDB, a collection name must be passed", 500);
  626. }
  627. try {
  628. $option = array('limit' => 1);
  629. $query = new MongoDB\Driver\Query($this->filter, $option);
  630. $table = $this->database . '.' . $table;
  631. $cursor = $this->manager->executeQuery($table, $query);
  632. $this->_clear();
  633. $return = $cursor->toArray();
  634. if ($return) {
  635. return $this->object_array($return[0]);
  636. } else {
  637. return null;
  638. }
  639. } catch (Exception $e) {
  640. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  641. show_error('table: ' . $table . '. filter: ' . json_encode($$this->filter) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine());
  642. } else {
  643. Throw new Exception("获取数据发生异常!");
  644. }
  645. }
  646. }
  647. /**
  648. * 将stdClass转换为array
  649. * @param $array
  650. * @return array
  651. */
  652. public function object_array($array)
  653. {
  654. if (is_object($array) && get_class($array) == "stdClass") {
  655. $array = (array)$array;
  656. }
  657. if(is_object($array) && get_class($array) == "MongoDB\BSON\ObjectID"){
  658. $array = (string)$array;
  659. }
  660. if (is_array($array)) {
  661. foreach ($array as $key => $value) {
  662. $array[$key] = $this->object_array($value);
  663. }
  664. }
  665. return $array;
  666. }
  667. public function set_pipeline($pipeline){
  668. $this->pipeline = $pipeline;
  669. return ($this);
  670. }
  671. public function lookup($lookup){
  672. if(is_array($lookup)){
  673. $this->pipeline['$lookup'] = $lookup;
  674. }
  675. return ($this);
  676. }
  677. /**
  678. * 聚合管道查询
  679. * @param string $table 数据库表单名称
  680. * @param array $pipeline 聚合管道操作
  681. * @return array
  682. * @throws Exception
  683. */
  684. public function aggregate($table, $group ,$project=NULL ,$is_cursor = FALSE)
  685. {
  686. try {
  687. $commands = array();
  688. $commands['aggregate'] = $table;
  689. if(is_array($project)) {
  690. $this->pipeline[] = array('$project'=>$project);
  691. }
  692. if(count($this->filter)>=1) {
  693. $this->pipeline[] = array('$match' => $this->filter);
  694. }
  695. if(array_key_exists("\$limit",$this->option)){
  696. $this->pipeline[] = array('$limit'=>$this->option['$limit']);
  697. }
  698. if(array_key_exists("\$skip",$this->option)){
  699. $this->pipeline[] = array('$skip'=>$this->option['$skip']);
  700. }
  701. if(is_array($group)) {
  702. $this->pipeline[] = array('$group'=>$group);
  703. }
  704. if(array_key_exists("sort",$this->option)){
  705. $this->pipeline[] = array('$sort'=>$this->option['sort']);
  706. }
  707. $commands['pipeline'] = $this->pipeline;
  708. $commands['allowDiskUse'] = true;
  709. if($this->db_version){
  710. $version = explode(".",$this->db_version);
  711. if($version[0] == 3 && $version[1]>2){
  712. $is_cursor =TRUE;
  713. }
  714. }
  715. if ($is_cursor) {
  716. $commands['cursor'] = new stdClass;
  717. }
  718. $command = new MongoDB\Driver\Command($commands);
  719. $database_name = str_replace('.', '', $this->database);
  720. $cursor = $this->manager->executeCommand($database_name, $command);
  721. if ($is_cursor) {
  722. $response = [];
  723. foreach ($cursor as $document) {
  724. $response[] = $document;
  725. }
  726. } else {
  727. $response = $cursor->toArray()[0]->result;
  728. }
  729. if (!empty($response)) {
  730. foreach ($response as &$value) {
  731. $value = (array)$value;
  732. }
  733. }
  734. $this->_clear();
  735. return $this->object_array($response);
  736. } catch (Exception $e) {
  737. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  738. show_error('table: ' . $table . '. pipeline: ' . json_encode($this->pipeline) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine());
  739. } else {
  740. Throw new Exception("聚合查询发生异常!");
  741. }
  742. }
  743. }
  744. /**
  745. * 创建(多个)索引
  746. * @param $table string 表名
  747. * @param array $indexes , 例:
  748. * [
  749. * [
  750. * 'key' => [
  751. * 'update_time' => 1 //要索引的字段, 升序还是降序
  752. * ],
  753. * 'name' => 'update_time', //索引名称
  754. * 'expireAfterSeconds' => 600 //可选, 索引参数, 这里的expireAfterSeconds表示这是一个ttl索引, 将在600s后被自动删除
  755. * ],
  756. * ]
  757. * @throws Exception
  758. */
  759. public function create_index($table, array $indexes)
  760. {
  761. $cmd = [
  762. 'createIndexes' => $table,
  763. 'indexes' => $indexes,
  764. ];
  765. $command = new MongoDB\Driver\Command($cmd);
  766. try {
  767. $this->manager->executeCommand($this->database, $command);
  768. } catch (Exception $e) {
  769. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  770. log_message(ERROR_LEVE, 'table: ' . $table . '. pipeline: ' . json_encode($cmd) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine());
  771. } else {
  772. Throw new Exception("创建索引发生异常!");
  773. }
  774. }
  775. }
  776. /**
  777. * 更新指定记录
  778. * @param string $table 数据库表单名称
  779. * @param array $data 数据记录
  780. * @param array $option 参数选项
  781. * @param bool $is_multi 是否同时更新多条记录
  782. * @return \MongoDB\Driver\WriteResult
  783. * @throws Exception
  784. */
  785. public function update($table, $data, $option = [], $is_multi = FALSE)
  786. {
  787. try {
  788. $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]);
  789. if (!$is_multi) {
  790. if(array_key_exists('_id',$data['update'])) {
  791. $data['update']['_id'] = $this->get_mongo_id($data['update']['_id']);
  792. }
  793. $bulk->update($data['filter'], array('$set' => $data['update']), $option);
  794. } else {
  795. foreach ($data as $one_data) {
  796. $bulk->update($one_data['filter'], array('$set' => $data['update']), $option);
  797. }
  798. }
  799. $table = $this->database . '.' . $table;
  800. $ret = $this->manager->executeBulkWrite($table, $bulk);
  801. $this->_clear();
  802. return $ret;
  803. } catch (Exception $e) {
  804. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  805. show_error('table: ' . $table . '. pipeline: ' . json_encode($data) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine());
  806. } else {
  807. Throw new Exception("更新数据发生异常!");
  808. }
  809. }
  810. }
  811. /**
  812. *
  813. * 删除记录
  814. * @param string $table 数据库表单名称
  815. * @param array $filter 更新的数据
  816. * @param bool $is_multi 是否同时删除多条记录
  817. * @param array $opinion mongo语句参数
  818. * @return \MongoDB\Driver\WriteResult
  819. * @throws Exception
  820. */
  821. public function delete($table)
  822. {
  823. try {
  824. $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]);
  825. $bulk->delete($this->filter, $this->option);
  826. $table = $this->database . '.' . $table;
  827. $ret = $this->manager->executeBulkWrite($table, $bulk);
  828. $this->_clear();
  829. return $ret;
  830. } catch (Exception $e) {
  831. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  832. show_error('table: ' . $table . '. pipeline: ' . json_encode($this->filter) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine());
  833. } else {
  834. Throw new Exception("删除数据发生异常!");
  835. }
  836. }
  837. }
  838. public function delete_all($table){
  839. try {
  840. $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]);
  841. $bulk->delete($this->filter, $this->option);
  842. $table = $this->database . '.' . $table;
  843. $ret = $this->manager->executeBulkWrite($table, $bulk);
  844. $this->_clear();
  845. return $ret;
  846. } catch (Exception $e) {
  847. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  848. show_error('table: ' . $table . '. pipeline: ' . json_encode($this->filter) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine());
  849. } else {
  850. Throw new Exception("删除数据发生异常!");
  851. }
  852. }
  853. }
  854. /**
  855. * 获取正则表达式
  856. * @param $pattern
  857. * @param string $flags
  858. * @param bool $preg 是否转义
  859. * @return \MongoDB\BSON\Regex
  860. * @throws Exception
  861. */
  862. public function get_regex($pattern, $flags = 'i', $preg = true)
  863. {
  864. try {
  865. #TD82216
  866. if ($preg) {
  867. $pattern = preg_quote($pattern);
  868. }
  869. return new MongoDB\BSON\Regex($pattern, $flags);
  870. } catch (Exception $e) {
  871. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  872. show_error('pattern: ' . $pattern . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine());
  873. } else {
  874. Throw new Exception("获取正则表达式发生异常!");
  875. }
  876. }
  877. }
  878. /**
  879. * 获取字段不同值的个数
  880. * @param string $table 表的名称
  881. * @param string $key 字段
  882. * @param array $filter 过滤条件
  883. * @return int 数值
  884. * @throws Exception
  885. */
  886. public function query_distinct_count($table, $key, $filter)
  887. {
  888. try {
  889. $param['distinct'] = $table;
  890. $param['key'] = $key;
  891. $param['query'] = $filter;
  892. $command = new MongoDB\Driver\Command($param);
  893. $cursor = $this->manager->executeCommand($this->database, $command);
  894. $result = $cursor->toArray();
  895. if (empty($result)) {
  896. return 0;
  897. }
  898. return count($result[0]->values);
  899. } catch (Exception $e) {
  900. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  901. log_message(ERROR_LEVE, 'pattern: ' . $table . ' key: ' . $key . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine());
  902. } else {
  903. Throw new Exception("获取指定字段的数量发生异常!");
  904. }
  905. }
  906. }
  907. /*
  908. * 获取数据查询记录数
  909. * @param string $table 数据库表单名称
  910. * @param array $filter 数据查询过滤条件
  911. * @return int 查询记录数
  912. * @throws Exception 数据库查询异常
  913. */
  914. public function query_nodistinct_count($table, $filter)
  915. {
  916. $param['aggregate'] = $table;
  917. $param['pipeline'] = array(
  918. array('$match' => $filter),
  919. array('$group' => array(
  920. '_id' => null,
  921. 'sum' => array(
  922. '$sum' => 1
  923. )
  924. )
  925. )
  926. );
  927. try {
  928. $param['cursor'] = new stdClass();
  929. $command = new MongoDB\Driver\Command($param);
  930. $cursor = $this->manager->executeCommand($this->database, $command);
  931. } catch (Exception $e) {
  932. $err_msg = sprintf("MongoDB Exception: %s", $e->getMessage());
  933. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  934. show_error($err_msg . $e->getFile() . $e->getLine());
  935. } else {
  936. throw new Exception("获取数据查询记录数发生异常!");
  937. }
  938. }
  939. $result = $cursor->toArray();
  940. if (empty($result)) {
  941. return 0;
  942. }
  943. return $result[0]->sum;
  944. }
  945. /**
  946. * 获取所有的记录数
  947. * @param string $table 表的名称
  948. * @param array $filter 过滤条件
  949. * @return int
  950. * @throws Exception
  951. */
  952. public function query_count($table, $filter)
  953. {
  954. $param['count'] = $table;
  955. $param['query'] = $filter;
  956. $command = new MongoDB\Driver\Command($param);
  957. try {
  958. $cursor = $this->manager->executeCommand($this->database, $command);
  959. } catch (Exception $e) {
  960. $err_msg = sprintf("MongoDB Exception: %s", $e->getMessage());
  961. if (isset($this->debug) == TRUE && $this->debug == TRUE) {
  962. show_error($err_msg . $e->getFile() . $e->getLine());
  963. } else {
  964. throw new Exception("获取所有的记录数发生异常!");
  965. }
  966. }
  967. $result = current($cursor->toArray());
  968. // Older server versions may return a float
  969. if (!isset($result->n) || !(is_integer($result->n) || is_float($result->n))) {
  970. throw new UnexpectedValueException('count command did not return a numeric "n" value');
  971. }
  972. return (integer)$result->n;
  973. }
  974. }