CI =& get_instance(); $this->CI->load->config('mongo_db'); $this->config = $this->CI->config->item('mongo_db'); $this->param = $param; $this->connect(); } /* * -------------------------------------------------------------------------------- * Prepare configuration for mongoDB connection * -------------------------------------------------------------------------------- * * Validate group name or autoload default group name from config file. * Validate all the properties present in config file of the group. */ private function prepare() { if (is_array($this->param) && count($this->param) > 0 && isset($this->param['activate']) == TRUE) { $this->activate = $this->param['activate']; } else if (isset($this->config['active']) && !empty($this->config['active'])) { $this->activate = $this->config['active']; } else { show_error("MongoDB configuration is missing.", 500); } if (isset($this->config[$this->activate]) == TRUE) { if (empty($this->config[$this->activate]['hostname'])) { show_error("Hostname missing from mongodb config group : {$this->activate}", 500); } else { $this->hostname = trim($this->config[$this->activate]['hostname']); } if (empty($this->config[$this->activate]['port'])) { show_error("Port number missing from mongodb config group : {$this->activate}", 500); } else { $this->port = trim($this->config[$this->activate]['port']); } if($this->config[$this->activate]['no_auth'] == FALSE){ if (empty($this->config[$this->activate]['username'])) { show_error("Username missing from mongodb config group : {$this->activate}", 500); } else { $this->username = trim($this->config[$this->activate]['username']); } if (empty($this->config[$this->activate]['password'])) { show_error("Password missing from mongodb config group : {$this->activate}", 500); } else { $this->password = trim($this->config[$this->activate]['password']); } } if (empty($this->config[$this->activate]['database'])) { show_error("Database name missing from mongodb config group : {$this->activate}", 500); } else { $this->database = trim($this->config[$this->activate]['database']); } if (empty($this->config[$this->activate]['db_debug'])) { $this->debug = FALSE; } else { $this->debug = $this->config[$this->activate]['db_debug']; } } else { show_error("mongodb config group : {$this->activate} does not exist.", 500); } } /** * -------------------------------------------------------------------------------- * Connect to MongoDB Database * -------------------------------------------------------------------------------- * * Connect to mongoDB database or throw exception with the error message. */ private function connect() { $this->prepare(); try { $dns = "mongodb://{$this->hostname}:{$this->port}"; if (isset($this->config[$this->activate]['no_auth']) == TRUE && $this->config[$this->activate]['no_auth'] == TRUE) { $options = array(); } else { $options = array('username' => $this->username, 'password' => $this->password); } $this->manager = new MongoDB\Driver\Manager($dns, $options); $this->db = $this->database; $this->db_version = $this->get_db_version(); } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("Unable to connect to MongoDB: {$e->getMessage()}", 500); } else { show_error("Unable to connect to MongoDB", 500); } } } public function get_manager(){ return $this->manager; } public function get_db_version(){ $command = new MongoDB\Driver\Command(array("buildinfo" => 1)); try { $cursor = $this->manager->executeCommand("admin", $command); $buildinfo = (array)$cursor->toArray()[0]; if(array_key_exists("version",$buildinfo)){ return $buildinfo['version']; }else{ return ""; } }catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("MongoDB query failed: {$e->getMessage()}", 500); } else { Throw new Exception("查询数据发生异常!"); } } } /** * 查询数据 * @param $tales */ public function get($table) { if (empty($table)) { show_error("In order to retrieve documents from MongoDB, a collection name must be passed", 500); } try { if (is_array($this->selects) && count($this->selects) > 0) { $this->option['projection'] = $this->selects; } $query = new MongoDB\Driver\Query($this->filter, $this->option); $table = $this->database . '.' . $table; $data = $this->manager->executeQuery($table, $query); $this->_clear(); $returns = []; foreach ($data as $doc) { $returns[] = $this->object_array($doc); } return $returns; } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("MongoDB query failed: {$e->getMessage()}", 500); } else { Throw new Exception("查询数据发生异常!"); } } } /** * 根据条件查询 * @param string $table * @param array $filter * @return mixed */ public function get_where($table = "", $filter = array()) { if (is_array($filter) && count($filter) > 0) { return $this->where($filter)->get($table); } else { show_error("Nothing passed to perform search or value is empty.", 500); } } public function select($includes = array(), $excludes = array()) { if (!is_array($includes)) { $includes = array(); } if (!is_array($excludes)) { $excludes = array(); } if (!empty($includes)) { foreach ($includes as $key => $col) { $this->selects[$col] = 1; } } if (!empty($excludes)) { foreach ($excludes as $col) { $this->selects[$col] = 0; } } return ($this); } public function where($filter, $value = null) { if (is_array($filter)) { foreach ($filter as $wh => $val) { $this->filter[$wh] = $val; } } elseif($filter) { $this->filter[$filter] = $value; } return $this; } public function where_or($filter = array()) { if (is_array($filter) && count($filter) > 0) { if (!isset($this->filter['$or']) || !is_array($this->filter['$or'])) { $this->filter['$or'] = array(); } foreach ($filter as $wh => $val) { $this->filter['$or'][] = array($wh => $val); } return ($this); } else { show_error("Where value should be an array.", 500); } } public function where_in($field = "", $in = array()) { if (empty($field)) { show_error("Mongo field is require to perform where in query.", 500); } if (is_array($in) && count($in) > 0) { $this->_w($field); $this->filter[$field]['$in'] = $in; return ($this); } else { show_error("in value should be an array.", 500); } } public function where_in_all($field = "", $in = array()) { if (empty($field)) { show_error("Mongo field is require to perform where all in query.", 500); } if (is_array($in) && count($in) > 0) { $this->_w($field); $this->filter[$field]['$all'] = $in; return ($this); } else { show_error("in value should be an array.", 500); } } public function where_not_in($field = "", $in = array()) { if (empty($field)) { show_error("Mongo field is require to perform where not in query.", 500); } if (is_array($in) && count($in) > 0) { $this->_w($field); $this->filter[$field]['$nin'] = $in; return ($this); } else { show_error("in value should be an array.", 500); } } public function where_gt($field = "", $x) { if (!isset($field)) { show_error("Mongo field is require to perform greater then query.", 500); } if (!isset($x)) { show_error("Mongo field's value is require to perform greater then query.", 500); } $this->_w($field); $this->filter[$field]['$gt'] = $x; return ($this); } /** * -------------------------------------------------------------------------------- * Where less than * -------------------------------------------------------------------------------- * * Get the documents where the value of a $field is less than $x * * @usage : $this->mongo_db->where_lt('foo', 20); */ public function where_lt($field = "", $x) { if (!isset($field)) { show_error("Mongo field is require to perform less then query.", 500); } if (!isset($x)) { show_error("Mongo field's value is require to perform less then query.", 500); } $this->_w($field); $this->filter[$field]['$lt'] = $x; return ($this); } /** * -------------------------------------------------------------------------------- * Where less than or equal to * -------------------------------------------------------------------------------- * * Get the documents where the value of a $field is less than or equal to $x * * @usage : $this->mongo_db->where_lte('foo', 20); */ public function where_lte($field = "", $x) { if (!isset($field)) { show_error("Mongo field is require to perform less then or equal to query.", 500); } if (!isset($x)) { show_error("Mongo field's value is require to perform less then or equal to query.", 500); } $this->_w($field); $this->filter[$field]['$lte'] = $x; return ($this); } /** * -------------------------------------------------------------------------------- * Where between * -------------------------------------------------------------------------------- * * Get the documents where the value of a $field is between $x and $y * * @usage : $this->mongo_db->where_between('foo', 20, 30); */ public function where_between($field = "", $x, $y) { if (!isset($field)) { show_error("Mongo field is require to perform greater then or equal to query.", 500); } if (!isset($x)) { show_error("Mongo field's start value is require to perform greater then or equal to query.", 500); } if (!isset($y)) { show_error("Mongo field's end value is require to perform greater then or equal to query.", 500); } $this->_w($field); $this->filter[$field]['$gte'] = $x; $this->filter[$field]['$lte'] = $y; return ($this); } /** * -------------------------------------------------------------------------------- * Where between and but not equal to * -------------------------------------------------------------------------------- * * Get the documents where the value of a $field is between but not equal to $x and $y * * @usage : $this->mongo_db->where_between_ne('foo', 20, 30); */ public function where_between_ne($field = "", $x, $y) { if (!isset($field)) { show_error("Mongo field is require to perform between and but not equal to query.", 500); } if (!isset($x)) { show_error("Mongo field's start value is require to perform between and but not equal to query.", 500); } if (!isset($y)) { show_error("Mongo field's end value is require to perform between and but not equal to query.", 500); } $this->_w($field); $this->filter[$field]['$gt'] = $x; $this->filter[$field]['$lt'] = $y; return ($this); } /** * -------------------------------------------------------------------------------- * Where not equal * -------------------------------------------------------------------------------- * * Get the documents where the value of a $field is not equal to $x * * @usage : $this->mongo_db->where_ne('foo', 1)->get('foobar'); */ public function where_ne($field = '', $x) { if (!isset($field)) { show_error("Mongo field is require to perform Where not equal to query.", 500); } if (!isset($x)) { show_error("Mongo field's value is require to perform Where not equal to query.", 500); } $this->_w($field); $this->filter[$field]['$ne'] = $x; return ($this); } /** * -------------------------------------------------------------------------------- * Like * -------------------------------------------------------------------------------- * * Get the documents where the (string) value of a $field is like a value. The defaults * allow for a case-insensitive search. * * @param $flags * Allows for the typical regular expression flags: * i = case insensitive * m = multiline * x = can contain comments * l = locale * s = dotall, "." matches everything, including newlines * u = match unicode * * @param $enable_start_wildcard * If set to anything other than TRUE, a starting line character "^" will be prepended * to the search value, representing only searching for a value at the start of * a new line. * * @param $enable_end_wildcard * If set to anything other than TRUE, an ending line character "$" will be appended * to the search value, representing only searching for a value at the end of * a line. * * @usage : $this->mongo_db->like('foo', 'bar', 'im', FALSE, TRUE); */ public function like($field = "", $value = "", $flags = "i") { if (empty($field)) { show_error("Mongo field is require to perform like query.", 500); } if (empty($value)) { show_error("Mongo field's value is require to like query.", 500); } $field = (string)trim($field); $this->_w($field); $value = (string)trim($value); $this->filter[$field] = $this->get_regex($value, $flags); return ($this); } public function create_like($value = "", $flags = "i") { if (empty($value)) { show_error("Mongo field's value is require to like query.", 500); } $value = (string)trim($value); return $this->get_regex($value, $flags); } /** * -------------------------------------------------------------------------------- * Count * -------------------------------------------------------------------------------- * * Count the documents based upon the passed parameters * * @usage : $this->mongo_db->count('foo'); */ public function count($collection = "") { if (empty($collection)) { show_error("In order to retrieve a count of documents from MongoDB, a collection name must be passed", 500); } $count = $this->query_count($collection, $this->filter); $this->_clear(); return ($count); } public function order_by($fields = array()) { if(is_array($fields)) { foreach ($fields as $col => $val) { if ($val == -1 || $val === FALSE || strtolower($val) == 'desc') { $this->option['sort'][$col] = -1; } else { $this->option['sort'][$col] = 1; } } } return ($this); } public function limit($x = 99999) { if ($x !== NULL && is_numeric($x) && $x >= 1) { $this->option['limit'] = (int)$x; } return ($this); } public function offset($x = 0) { if ($x !== NULL && is_numeric($x) && $x >= 1) { $this->option['skip'] = (int)$x; } return ($this); } public function set_wheres($wheres) { if (is_array($wheres) && count($wheres) > 0) { $this->filter = $wheres; } return ($this); } public function set($fields, $value = NULL) { if (is_string($fields)) { $this->updates['$set'][$fields] = $value; } elseif (is_array($fields)) { foreach ($fields as $field => $value) { $this->updates['$set'][$field] = $value; } } return $this; } public function update_all($table, $option = []) { try { $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]); $this->option = array('multi' => true); $bulk->update($this->filter, $this->updates, $this->option); $table = $this->database . '.' . $table; $ret = $this->manager->executeBulkWrite($table, $bulk); $this->_clear(); return $ret; } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error('table: ' . $table . '. pipeline: ' . json_encode($this->filter) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine()); } else { Throw new Exception("更新数据发生异常!"); } } } /** * -------------------------------------------------------------------------------- * _clear * -------------------------------------------------------------------------------- * * Resets the class variables to default settings */ private function _clear() { $this->filter = array(); $this->option = array(); $this->pipeline = array(); $this->selects = array(); $this->limit = 999999; $this->offset = 0; } /** * -------------------------------------------------------------------------------- * Where initializer * -------------------------------------------------------------------------------- * * Prepares parameters for insertion in $wheres array(). */ private function _w($param) { if (!isset($this->filter[$param])) { $this->filter[$param] = array(); } } /** * 获取MongoDB ObjectID * @param $_id * @return \MongoDB\BSON\objectID */ public function get_mongo_id($_id) { if (is_string($_id)) { try { $_id = new MongoDB\BSON\objectID($_id); } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error('get_mongo_id:' . $_id . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine()); } else { Throw new Exception("获取MongoDB ObjectID 发生异常!"); } } } return $_id; } /** * ָ插入一或多条数据 * @param string $table 数据库表单名称 * @param array $data 需要插入的数据 * @param bool $is_multi 是否批处理 * @return bool ִ执行结果 * @throws Exception */ public function insert($table, $data, $is_multi = FALSE) { try { $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]); if (!$is_multi) { $bulk->insert($data); } else { foreach ($data as $one_data) { $bulk->insert($one_data); } } $table = $this->database . '.' . $table; return $this->manager->executeBulkWrite($table, $bulk); } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error('table: ' . $table . '. data: ' . json_encode($data) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine()); } else { Throw new Exception("插入数据发生异常!"); } } } /** * 获取单条数据库数据 * @param string $table 数据库表单名称 * @param array $filter 过滤条件 * @param array $option 列、排序、分页等 * @return objects 符合条件数据 * @throws Exception */ public function find_one($table) { if (empty($table)) { show_error("In order to retrieve documents from MongoDB, a collection name must be passed", 500); } try { $option = array('limit' => 1); $query = new MongoDB\Driver\Query($this->filter, $option); $table = $this->database . '.' . $table; $cursor = $this->manager->executeQuery($table, $query); $this->_clear(); $return = $cursor->toArray(); if ($return) { return $this->object_array($return[0]); } else { return null; } } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error('table: ' . $table . '. filter: ' . json_encode($$this->filter) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine()); } else { Throw new Exception("获取数据发生异常!"); } } } /** * 将stdClass转换为array * @param $array * @return array */ public function object_array($array) { if (is_object($array) && get_class($array) == "stdClass") { $array = (array)$array; } if(is_object($array) && get_class($array) == "MongoDB\BSON\ObjectID"){ $array = (string)$array; } if (is_array($array)) { foreach ($array as $key => $value) { $array[$key] = $this->object_array($value); } } return $array; } public function set_pipeline($pipeline){ $this->pipeline = $pipeline; return ($this); } public function lookup($lookup){ if(is_array($lookup)){ $this->pipeline['$lookup'] = $lookup; } return ($this); } /** * 聚合管道查询 * @param string $table 数据库表单名称 * @param array $pipeline 聚合管道操作 * @return array * @throws Exception */ public function aggregate($table, $group ,$project=NULL ,$is_cursor = FALSE) { try { $commands = array(); $commands['aggregate'] = $table; if(is_array($project)) { $this->pipeline[] = array('$project'=>$project); } if(count($this->filter)>=1) { $this->pipeline[] = array('$match' => $this->filter); } if(array_key_exists("\$limit",$this->option)){ $this->pipeline[] = array('$limit'=>$this->option['$limit']); } if(array_key_exists("\$skip",$this->option)){ $this->pipeline[] = array('$skip'=>$this->option['$skip']); } if(is_array($group)) { $this->pipeline[] = array('$group'=>$group); } if(array_key_exists("sort",$this->option)){ $this->pipeline[] = array('$sort'=>$this->option['sort']); } $commands['pipeline'] = $this->pipeline; $commands['allowDiskUse'] = true; if($this->db_version){ $version = explode(".",$this->db_version); if($version[0] == 3 && $version[1]>2){ $is_cursor =TRUE; } } if ($is_cursor) { $commands['cursor'] = new stdClass; } $command = new MongoDB\Driver\Command($commands); $database_name = str_replace('.', '', $this->database); $cursor = $this->manager->executeCommand($database_name, $command); if ($is_cursor) { $response = []; foreach ($cursor as $document) { $response[] = $document; } } else { $response = $cursor->toArray()[0]->result; } if (!empty($response)) { foreach ($response as &$value) { $value = (array)$value; } } $this->_clear(); return $this->object_array($response); } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error('table: ' . $table . '. pipeline: ' . json_encode($this->pipeline) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine()); } else { Throw new Exception("聚合查询发生异常!"); } } } /** * 创建(多个)索引 * @param $table string 表名 * @param array $indexes , 例: * [ * [ * 'key' => [ * 'update_time' => 1 //要索引的字段, 升序还是降序 * ], * 'name' => 'update_time', //索引名称 * 'expireAfterSeconds' => 600 //可选, 索引参数, 这里的expireAfterSeconds表示这是一个ttl索引, 将在600s后被自动删除 * ], * ] * @throws Exception */ public function create_index($table, array $indexes) { $cmd = [ 'createIndexes' => $table, 'indexes' => $indexes, ]; $command = new MongoDB\Driver\Command($cmd); try { $this->manager->executeCommand($this->database, $command); } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { log_message(ERROR_LEVE, 'table: ' . $table . '. pipeline: ' . json_encode($cmd) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine()); } else { Throw new Exception("创建索引发生异常!"); } } } /** * 更新指定记录 * @param string $table 数据库表单名称 * @param array $data 数据记录 * @param array $option 参数选项 * @param bool $is_multi 是否同时更新多条记录 * @return \MongoDB\Driver\WriteResult * @throws Exception */ public function update($table, $data, $option = [], $is_multi = FALSE) { try { $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]); if (!$is_multi) { if(array_key_exists('_id',$data['update'])) { $data['update']['_id'] = $this->get_mongo_id($data['update']['_id']); } $bulk->update($data['filter'], array('$set' => $data['update']), $option); } else { foreach ($data as $one_data) { $bulk->update($one_data['filter'], array('$set' => $data['update']), $option); } } $table = $this->database . '.' . $table; $ret = $this->manager->executeBulkWrite($table, $bulk); $this->_clear(); return $ret; } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error('table: ' . $table . '. pipeline: ' . json_encode($data) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine()); } else { Throw new Exception("更新数据发生异常!"); } } } /** * * 删除记录 * @param string $table 数据库表单名称 * @param array $filter 更新的数据 * @param bool $is_multi 是否同时删除多条记录 * @param array $opinion mongo语句参数 * @return \MongoDB\Driver\WriteResult * @throws Exception */ public function delete($table) { try { $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]); $bulk->delete($this->filter, $this->option); $table = $this->database . '.' . $table; $ret = $this->manager->executeBulkWrite($table, $bulk); $this->_clear(); return $ret; } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error('table: ' . $table . '. pipeline: ' . json_encode($this->filter) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine()); } else { Throw new Exception("删除数据发生异常!"); } } } public function delete_all($table){ try { $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]); $bulk->delete($this->filter, $this->option); $table = $this->database . '.' . $table; $ret = $this->manager->executeBulkWrite($table, $bulk); $this->_clear(); return $ret; } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error('table: ' . $table . '. pipeline: ' . json_encode($this->filter) . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine()); } else { Throw new Exception("删除数据发生异常!"); } } } /** * 获取正则表达式 * @param $pattern * @param string $flags * @param bool $preg 是否转义 * @return \MongoDB\BSON\Regex * @throws Exception */ public function get_regex($pattern, $flags = 'i', $preg = true) { try { #TD82216 if ($preg) { $pattern = preg_quote($pattern); } return new MongoDB\BSON\Regex($pattern, $flags); } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error('pattern: ' . $pattern . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine()); } else { Throw new Exception("获取正则表达式发生异常!"); } } } /** * 获取字段不同值的个数 * @param string $table 表的名称 * @param string $key 字段 * @param array $filter 过滤条件 * @return int 数值 * @throws Exception */ public function query_distinct_count($table, $key, $filter) { try { $param['distinct'] = $table; $param['key'] = $key; $param['query'] = $filter; $command = new MongoDB\Driver\Command($param); $cursor = $this->manager->executeCommand($this->database, $command); $result = $cursor->toArray(); if (empty($result)) { return 0; } return count($result[0]->values); } catch (Exception $e) { if (isset($this->debug) == TRUE && $this->debug == TRUE) { log_message(ERROR_LEVE, 'pattern: ' . $table . ' key: ' . $key . '. MongoDB Exception: ' . $e->getMessage(), $e->getFile(), $e->getLine()); } else { Throw new Exception("获取指定字段的数量发生异常!"); } } } /* * 获取数据查询记录数 * @param string $table 数据库表单名称 * @param array $filter 数据查询过滤条件 * @return int 查询记录数 * @throws Exception 数据库查询异常 */ public function query_nodistinct_count($table, $filter) { $param['aggregate'] = $table; $param['pipeline'] = array( array('$match' => $filter), array('$group' => array( '_id' => null, 'sum' => array( '$sum' => 1 ) ) ) ); try { $param['cursor'] = new stdClass(); $command = new MongoDB\Driver\Command($param); $cursor = $this->manager->executeCommand($this->database, $command); } catch (Exception $e) { $err_msg = sprintf("MongoDB Exception: %s", $e->getMessage()); if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error($err_msg . $e->getFile() . $e->getLine()); } else { throw new Exception("获取数据查询记录数发生异常!"); } } $result = $cursor->toArray(); if (empty($result)) { return 0; } return $result[0]->sum; } /** * 获取所有的记录数 * @param string $table 表的名称 * @param array $filter 过滤条件 * @return int * @throws Exception */ public function query_count($table, $filter) { $param['count'] = $table; $param['query'] = $filter; $command = new MongoDB\Driver\Command($param); try { $cursor = $this->manager->executeCommand($this->database, $command); } catch (Exception $e) { $err_msg = sprintf("MongoDB Exception: %s", $e->getMessage()); if (isset($this->debug) == TRUE && $this->debug == TRUE) { show_error($err_msg . $e->getFile() . $e->getLine()); } else { throw new Exception("获取所有的记录数发生异常!"); } } $result = current($cursor->toArray()); // Older server versions may return a float if (!isset($result->n) || !(is_integer($result->n) || is_float($result->n))) { throw new UnexpectedValueException('count command did not return a numeric "n" value'); } return (integer)$result->n; } }