CI =& get_instance(); $this->CI->load->config('mongo_db'); $this->config = $this->CI->config->item('mongo_db'); $this->param = $param; $this->connect(); } /** * -------------------------------------------------------------------------------- * Class Destructor * -------------------------------------------------------------------------------- * * Close all open connections. */ function __destruct() { if(is_object($this->connect)) { //$this->connect->close(); } } /** * -------------------------------------------------------------------------------- * 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(isset($this->config[$this->activate]['no_auth']) == FALSE && 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(isset($this->config[$this->activate]['no_auth']) == FALSE && 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']; } if(empty($this->config[$this->activate]['return_as'])) { $this->return_as = 'array'; } else { $this->return_as = $this->config[$this->activate]['return_as']; } if(empty($this->config[$this->activate]['legacy_support'])) { $this->legacy_support = false; } else { $this->legacy_support = $this->config[$this->activate]['legacy_support']; } if(empty($this->config[$this->activate]['read_preference']) || !isset($this->config[$this->activate]['read_preference'])) { $this->read_preference = MongoDB\Driver\ReadPreference::RP_PRIMARY; } else { $this->read_preference = $this->config[$this->activate]['read_preference']; } if(empty($this->config[$this->activate]['read_concern']) || !isset($this->config[$this->activate]['read_concern'])) { $this->read_concern = MongoDB\Driver\ReadConcern::MAJORITY; } else { $this->read_concern = $this->config[$this->activate]['read_concern']; } } else { show_error("mongodb config group : {$this->activate} does not exist.", 500); } } /** * Sets the return as to object or array * This is useful if library is used in another library to avoid issue if config values are different * * @param string $value */ public function set_return_as($value) { if(!in_array($value, ['array', 'object'])) { show_error("Invalid Return As Type"); } $this->return_as = $value; } /** * -------------------------------------------------------------------------------- * 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}/{$this->database}"; 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->connect = $this->db = new MongoDB\Driver\Manager($dns, $options); } catch (MongoDB\Driver\Exception\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); } } } /** * -------------------------------------------------------------------------------- * //! Insert * -------------------------------------------------------------------------------- * * Insert a new document into the passed collection * * @usage : $this->mongo_db->insert('foo', $data = array()); */ public function insert($collection = "", $insert = array()) { if (empty($collection)) { show_error("No Mongo collection selected to insert into", 500); } if (!is_array($insert) || count($insert) == 0) { show_error("Nothing to insert into Mongo collection or insert is not an array", 500); } if(isset($insert['_id']) === false) { $insert['_id'] = new MongoDB\BSON\ObjectId; } $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert($insert); $writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000); try { $write = $this->db->executeBulkWrite($this->database.".".$collection, $bulk, $writeConcern); return $this->convert_document_id($insert); } // Check if the write concern could not be fulfilled catch (MongoDB\Driver\Exception\BulkWriteException $e) { $result = $e->getWriteResult(); if ($writeConcernError = $result->getWriteConcernError()) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("WriteConcern failure : {$writeConcernError->getMessage()}", 500); } else { show_error("WriteConcern failure", 500); } } } // Check if any general error occured. catch (MongoDB\Driver\Exception\Exception $e) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("Insert of data into MongoDB failed: {$e->getMessage()}", 500); } else { show_error("Insert of data into MongoDB failed", 500); } } } /** * -------------------------------------------------------------------------------- * Batch Insert * -------------------------------------------------------------------------------- * * Insert a multiple document into the collection * * @usage : $this->mongo_db->batch_insert('foo', $data = array()); * @return : bool or array : if query fail then false else array of _id successfully inserted. */ public function batch_insert($collection = "", $insert = array()) { if (empty($collection)) { show_error("No Mongo collection selected to insert into", 500); } if (!is_array($insert) || count($insert) == 0) { show_error("Nothing to insert into Mongo collection or insert is not an array", 500); } $doc = new MongoDB\Driver\BulkWrite(); foreach ($insert as $ins) { if(isset($ins['_id']) === false) { $ins['_id'] = new MongoDB\BSON\ObjectId; } $doc->insert($ins); } $writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000); try { $result = $this->db->executeBulkWrite($this->database.".".$collection, $doc, $writeConcern); return $result; } // Check if the write concern could not be fulfilled catch (MongoDB\Driver\Exception\BulkWriteException $e) { $result = $e->getWriteResult(); if ($writeConcernError = $result->getWriteConcernError()) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("WriteConcern failure : {$writeConcernError->getMessage()}", 500); } else { show_error("WriteConcern failure", 500); } } } // Check if any general error occured. catch (MongoDB\Driver\Exception\Exception $e) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("Insert of data into MongoDB failed: {$e->getMessage()}", 500); } else { show_error("Insert of data into MongoDB failed", 500); } } } /** * -------------------------------------------------------------------------------- * //! Select * -------------------------------------------------------------------------------- * * Determine which fields to include OR which to exclude during the query process. * If you want to only choose fields to exclude, leave $includes an empty array(). * * @usage: $this->mongo_db->select(array('foo', 'bar'))->get('foobar'); */ 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) { if(is_array($col)){ //support $elemMatch in select $this->selects[$key] = $col; }else{ $this->selects[$col] = 1; } } } if ( ! empty($excludes)) { foreach ($excludes as $col) { $this->selects[$col] = 0; } } return ($this); } /** * -------------------------------------------------------------------------------- * //! Where * -------------------------------------------------------------------------------- * * Get the documents based on these search parameters. The $wheres array should * be an associative array with the field as the key and the value as the search * criteria. * * @usage : $this->mongo_db->where(array('foo' => 'bar'))->get('foobar'); */ public function where($wheres, $value = null) { if (is_array($wheres)) { foreach ($wheres as $wh => $val) { $this->wheres[$wh] = $val; } } else { $this->wheres[$wheres] = $value; } return $this; } /** * -------------------------------------------------------------------------------- * or where * -------------------------------------------------------------------------------- * * Get the documents where the value of a $field may be something else * * @usage : $this->mongo_db->where_or(array('foo'=>'bar', 'bar'=>'foo'))->get('foobar'); */ public function where_or($wheres = array()) { if (is_array($wheres) && count($wheres) > 0) { if ( ! isset($this->wheres['$or']) || ! is_array($this->wheres['$or'])) { $this->wheres['$or'] = array(); } foreach ($wheres as $wh => $val) { $this->wheres['$or'][] = array($wh=>$val); } return ($this); } else { show_error("Where value should be an array.", 500); } } /** * -------------------------------------------------------------------------------- * Where in * -------------------------------------------------------------------------------- * * Get the documents where the value of a $field is in a given $in array(). * * @usage : $this->mongo_db->where_in('foo', array('bar', 'zoo', 'blah'))->get('foobar'); */ 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->wheres[$field]['$in'] = $in; return ($this); } else { show_error("in value should be an array.", 500); } } /** * -------------------------------------------------------------------------------- * Where in all * -------------------------------------------------------------------------------- * * Get the documents where the value of a $field is in all of a given $in array(). * * @usage : $this->mongo_db->where_in_all('foo', array('bar', 'zoo', 'blah'))->get('foobar'); */ 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->wheres[$field]['$all'] = $in; return ($this); } else { show_error("in value should be an array.", 500); } } /** * -------------------------------------------------------------------------------- * Where not in * -------------------------------------------------------------------------------- * * Get the documents where the value of a $field is not in a given $in array(). * * @usage : $this->mongo_db->where_not_in('foo', array('bar', 'zoo', 'blah'))->get('foobar'); */ 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->wheres[$field]['$nin'] = $in; return ($this); } else { show_error("in value should be an array.", 500); } } /** * -------------------------------------------------------------------------------- * Where greater than * -------------------------------------------------------------------------------- * * Get the documents where the value of a $field is greater than $x * * @usage : $this->mongo_db->where_gt('foo', 20); */ 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->wheres[$field]['$gt'] = $x; return ($this); } /** * -------------------------------------------------------------------------------- * Where greater than or equal to * -------------------------------------------------------------------------------- * * Get the documents where the value of a $field is greater than or equal to $x * * @usage : $this->mongo_db->where_gte('foo', 20); */ public function where_gte($field = "", $x) { if (!isset($field)) { show_error("Mongo field is require to perform greater then or equal query.", 500); } if (!isset($x)) { show_error("Mongo field's value is require to perform greater then or equal query.", 500); } $this->_w($field); $this->wheres[$field]['$gte'] = $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->wheres[$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->wheres[$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->wheres[$field]['$gte'] = $x; $this->wheres[$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->wheres[$field]['$gt'] = $x; $this->wheres[$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->wheres[$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", $enable_start_wildcard = TRUE, $enable_end_wildcard = TRUE) { 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); $value = quotemeta($value); if ($enable_start_wildcard !== TRUE) { $value = "^" . $value; } if ($enable_end_wildcard !== TRUE) { $value .= "$"; } $regex = "/$value/$flags"; $this->wheres[$field] = new MongoRegex($regex); return ($this); } /** * -------------------------------------------------------------------------------- * // Get * -------------------------------------------------------------------------------- * * Get the documents based upon the passed parameters * * @usage : $this->mongo_db->get('foo'); */ public function get($collection = "") { if (empty($collection)) { show_error("In order to retrieve documents from MongoDB, a collection name must be passed", 500); } try{ $read_concern = new MongoDB\Driver\ReadConcern($this->read_concern); $read_preference = new MongoDB\Driver\ReadPreference($this->read_preference); $options = array(); $options['projection'] = $this->selects; $options['sort'] = $this->sorts; $options['skip'] = (int) $this->offset; $options['limit'] = (int) $this->limit; $options['readConcern'] = $read_concern; $query = new MongoDB\Driver\Query($this->wheres, $options); $cursor = $this->db->executeQuery($this->database.".".$collection, $query, $read_preference); // Clear $this->_clear(); $returns = array(); if ($cursor instanceof MongoDB\Driver\Cursor) { $it = new \IteratorIterator($cursor); $it->rewind(); while ($doc = (array)$it->current()) { if ($this->return_as == 'object') { $returns[] = (object) $this->convert_document_id($doc); } else { $returns[] = (array) $this->convert_document_id($doc); } $it->next(); } } if ($this->return_as == 'object') { return (object)$returns; } else { return $returns; } } catch (MongoDB\Driver\Exception $e) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("MongoDB query failed: {$e->getMessage()}", 500); } else { show_error("MongoDB query failed.", 500); } } } /** * -------------------------------------------------------------------------------- * // Get where * -------------------------------------------------------------------------------- * * Get the documents based upon the passed parameters * * @usage : $this->mongo_db->get_where('foo', array('bar' => 'something')); */ public function get_where($collection = "", $where = array()) { if (is_array($where) && count($where) > 0) { return $this->where($where) ->get($collection); } else { show_error("Nothing passed to perform search or value is empty.", 500); } } /** * -------------------------------------------------------------------------------- * // Find One * -------------------------------------------------------------------------------- * * Get the single document based upon the passed parameters * * @usage : $this->mongo_db->find_one('foo'); */ public function find_one($collection = "") { if (empty($collection)) { show_error("In order to retrieve documents from MongoDB, a collection name must be passed", 500); } try{ $read_concern = new MongoDB\Driver\ReadConcern($this->read_concern); $read_preference = new MongoDB\Driver\ReadPreference($this->read_preference); $options = array(); $options['projection'] = $this->selects; $options['sort'] = $this->sorts; $options['skip'] = (int) $this->offset; $options['limit'] = (int) 1; $options['readConcern'] = $read_concern; $query = new MongoDB\Driver\Query($this->wheres, $options); $cursor = $this->db->executeQuery($this->database.".".$collection, $query, $read_preference); // Clear $this->_clear(); $returns = array(); if ($cursor instanceof MongoDB\Driver\Cursor) { $it = new \IteratorIterator($cursor); $it->rewind(); while ($doc = (array)$it->current()) { if ($this->return_as == 'object') { $returns[] = (object) $this->convert_document_id($doc); } else { $returns[] = (array) $this->convert_document_id($doc); } $it->next(); } } if ($this->return_as == 'object') { return (object)$returns; } else { return $returns; } } catch (MongoDB\Driver\Exception $e) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("MongoDB query failed: {$e->getMessage()}", 500); } else { show_error("MongoDB query failed.", 500); } } } /** * -------------------------------------------------------------------------------- * 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 documents from MongoDB, a collection name must be passed", 500); } try{ $read_concern = new MongoDB\Driver\ReadConcern($this->read_concern); $read_preference = new MongoDB\Driver\ReadPreference($this->read_preference); $options = array(); $options['projection'] = array('_id'=>1); $options['sort'] = $this->sorts; $options['skip'] = (int) $this->offset; $options['limit'] = (int) $this->limit; $options['readConcern'] = $read_concern; $query = new MongoDB\Driver\Query($this->wheres, $options); $cursor = $this->db->executeQuery($this->database.".".$collection, $query, $read_preference); $array = $cursor->toArray(); // Clear $this->_clear(); return count($array); } catch (MongoDB\Driver\Exception $e) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("MongoDB query failed: {$e->getMessage()}", 500); } else { show_error("MongoDB query failed.", 500); } } } /** * -------------------------------------------------------------------------------- * Count All Results * -------------------------------------------------------------------------------- * * Alias to count method for compatibility with CI Query Builder * * @usage : $this->mongo_db->count('foo'); */ public function count_all_results($collection = "") { return $this->count($collection); } /** * -------------------------------------------------------------------------------- * Set * -------------------------------------------------------------------------------- * * Sets a field to a value * * @usage: $this->mongo_db->where(array('blog_id'=>123))->set('posted', 1)->update('blog_posts'); * @usage: $this->mongo_db->where(array('blog_id'=>123))->set(array('posted' => 1, 'time' => time()))->update('blog_posts'); */ public function set($fields, $value = NULL) { $this->_u('$set'); 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; } /** * -------------------------------------------------------------------------------- * Unset * -------------------------------------------------------------------------------- * * Unsets a field (or fields) * * @usage: $this->mongo_db->where(array('blog_id'=>123))->unset('posted')->update('blog_posts'); * @usage: $this->mongo_db->where(array('blog_id'=>123))->set(array('posted','time'))->update('blog_posts'); */ public function unset_field($fields) { $this->_u('$unset'); if (is_string($fields)) { $this->updates['$unset'][$fields] = 1; } elseif (is_array($fields)) { foreach ($fields as $field) { $this->updates['$unset'][$field] = 1; } } return $this; } /** * -------------------------------------------------------------------------------- * Add to set * -------------------------------------------------------------------------------- * * Adds value to the array only if its not in the array already * * @usage: $this->mongo_db->where(array('blog_id'=>123))->addtoset('tags', 'php')->update('blog_posts'); * @usage: $this->mongo_db->where(array('blog_id'=>123))->addtoset('tags', array('php', 'codeigniter', 'mongodb'))->update('blog_posts'); */ public function addtoset($field, $values) { $this->_u('$addToSet'); if (is_string($values)) { $this->updates['$addToSet'][$field] = $values; } elseif (is_array($values)) { $this->updates['$addToSet'][$field] = array('$each' => $values); } return $this; } /** * -------------------------------------------------------------------------------- * Push * -------------------------------------------------------------------------------- * * Pushes values into a field (field must be an array) * * @usage: $this->mongo_db->where(array('blog_id'=>123))->push('comments', array('text'=>'Hello world'))->update('blog_posts'); * @usage: $this->mongo_db->where(array('blog_id'=>123))->push(array('comments' => array('text'=>'Hello world')), 'viewed_by' => array('Alex')->update('blog_posts'); */ public function push($fields, $value = array()) { $this->_u('$push'); if (is_string($fields)) { $this->updates['$push'][$fields] = $value; } elseif (is_array($fields)) { foreach ($fields as $field => $value) { $this->updates['$push'][$field] = $value; } } return $this; } /** * -------------------------------------------------------------------------------- * Pop * -------------------------------------------------------------------------------- * * Pops the last value from a field (field must be an array) * * @usage: $this->mongo_db->where(array('blog_id'=>123))->pop('comments')->update('blog_posts'); * @usage: $this->mongo_db->where(array('blog_id'=>123))->pop(array('comments', 'viewed_by'))->update('blog_posts'); */ public function pop($field) { $this->_u('$pop'); if (is_string($field)) { $this->updates['$pop'][$field] = -1; } elseif (is_array($field)) { foreach ($field as $pop_field) { $this->updates['$pop'][$pop_field] = -1; } } return $this; } /** * -------------------------------------------------------------------------------- * Pull * -------------------------------------------------------------------------------- * * Removes by an array by the value of a field * * @usage: $this->mongo_db->pull('comments', array('comment_id'=>123))->update('blog_posts'); */ public function pull($field = "", $value = array()) { $this->_u('$pull'); $this->updates['$pull'] = array($field => $value); return $this; } /** * -------------------------------------------------------------------------------- * Rename field * -------------------------------------------------------------------------------- * * Renames a field * * @usage: $this->mongo_db->where(array('blog_id'=>123))->rename_field('posted_by', 'author')->update('blog_posts'); */ public function rename_field($old, $new) { $this->_u('$rename'); $this->updates['$rename'] = array($old => $new); return $this; } /** * -------------------------------------------------------------------------------- * Inc * -------------------------------------------------------------------------------- * * Increments the value of a field * * @usage: $this->mongo_db->where(array('blog_id'=>123))->inc(array('num_comments' => 1))->update('blog_posts'); */ public function inc($fields = array(), $value = 0) { $this->_u('$inc'); if (is_string($fields)) { $this->updates['$inc'][$fields] = $value; } elseif (is_array($fields)) { foreach ($fields as $field => $value) { $this->updates['$inc'][$field] = $value; } } return $this; } /** * -------------------------------------------------------------------------------- * Multiple * -------------------------------------------------------------------------------- * * Multiple the value of a field * * @usage: $this->mongo_db->where(array('blog_id'=>123))->mul(array('num_comments' => 3))->update('blog_posts'); */ public function mul($fields = array(), $value = 0) { $this->_u('$mul'); if (is_string($fields)) { $this->updates['$mul'][$fields] = $value; } elseif (is_array($fields)) { foreach ($fields as $field => $value) { $this->updates['$mul'][$field] = $value; } } return $this; } /** * -------------------------------------------------------------------------------- * Maximum * -------------------------------------------------------------------------------- * * The $max operator updates the value of the field to a specified value if the specified value is greater than the current value of the field. * * @usage: $this->mongo_db->where(array('blog_id'=>123))->max(array('num_comments' => 3))->update('blog_posts'); */ public function max($fields = array(), $value = 0) { $this->_u('$max'); if (is_string($fields)) { $this->updates['$max'][$fields] = $value; } elseif (is_array($fields)) { foreach ($fields as $field => $value) { $this->updates['$max'][$field] = $value; } } return $this; } /** * -------------------------------------------------------------------------------- * Minimum * -------------------------------------------------------------------------------- * * The $min updates the value of the field to a specified value if the specified value is less than the current value of the field. * * @usage: $this->mongo_db->where(array('blog_id'=>123))->min(array('num_comments' => 3))->update('blog_posts'); */ public function min($fields = array(), $value = 0) { $this->_u('$min'); if (is_string($fields)) { $this->updates['$min'][$fields] = $value; } elseif (is_array($fields)) { foreach ($fields as $field => $value) { $this->updates['$min'][$field] = $value; } } return $this; } /** * -------------------------------------------------------------------------------- * //! distinct * -------------------------------------------------------------------------------- * * Finds the distinct values for a specified field across a single collection * * @usage: $this->mongo_db->distinct('collection', 'field'); */ public function distinct($collection = "", $field="") { if (empty($collection)) { show_error("No Mongo collection selected for update", 500); } if (empty($field)) { show_error("Need Collection field information for performing distinct query", 500); } try { $documents = $this->db->{$collection}->distinct($field, $this->wheres); $this->_clear(); if ($this->return_as == 'object') { return (object)$documents; } else { return $documents; } } catch (MongoCursorException $e) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("MongoDB Distinct Query Failed: {$e->getMessage()}", 500); } else { show_error("MongoDB failed", 500); } } } /** * -------------------------------------------------------------------------------- * //! Update * -------------------------------------------------------------------------------- * * Updates a single document in Mongo * * @usage: $this->mongo_db->update('foo', $data = array()); */ public function update($collection = "", $options = array()) { if (empty($collection)) { show_error("No Mongo collection selected for update", 500); } $bulk = new MongoDB\Driver\BulkWrite(); $bulk->update($this->wheres, $this->updates, $options); $writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000); try { $write = $this->db->executeBulkWrite($this->database.".".$collection, $bulk, $writeConcern); $this->_clear(); return $write; } // Check if the write concern could not be fulfilled catch (MongoDB\Driver\Exception\BulkWriteException $e) { $result = $e->getWriteResult(); if ($writeConcernError = $result->getWriteConcernError()) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("WriteConcern failure : {$writeConcernError->getMessage()}", 500); } else { show_error("WriteConcern failure", 500); } } } // Check if any general error occured. catch (MongoDB\Driver\Exception\Exception $e) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("Update of data into MongoDB failed: {$e->getMessage()}", 500); } else { show_error("Update of data into MongoDB failed", 500); } } } /** * -------------------------------------------------------------------------------- * Update all * -------------------------------------------------------------------------------- * * Updates a collection of documents * * @usage: $this->mongo_db->update_all('foo', $data = array()); */ public function update_all($collection = "", $data = array(), $options = array()) { if (empty($collection)) { show_error("No Mongo collection selected to update", 500); } if (is_array($data) && count($data) > 0) { $this->updates = array_merge($data, $this->updates); } if (count($this->updates) == 0) { show_error("Nothing to update in Mongo collection or update is not an array", 500); } $options = array_merge(array('multi' => TRUE), $options); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->update($this->wheres, $this->updates, $options); $writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000); try { $write = $this->db->executeBulkWrite($this->database.".".$collection, $bulk, $writeConcern); $this->_clear(); return $write; } // Check if the write concern could not be fulfilled catch (MongoDB\Driver\Exception\BulkWriteException $e) { $result = $e->getWriteResult(); if ($writeConcernError = $result->getWriteConcernError()) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("WriteConcern failure : {$writeConcernError->getMessage()}", 500); } else { show_error("WriteConcern failure", 500); } } } // Check if any general error occured. catch (MongoDB\Driver\Exception\Exception $e) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("Update of data into MongoDB failed: {$e->getMessage()}", 500); } else { show_error("Update of data into MongoDB failed", 500); } } } /** * -------------------------------------------------------------------------------- * //! Delete * -------------------------------------------------------------------------------- * * delete document from the passed collection based upon certain criteria * * @usage : $this->mongo_db->delete('foo'); */ public function delete($collection = "") { if (empty($collection)) { show_error("No Mongo collection selected for update", 500); } $options = array('limit'=>true); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->delete($this->wheres, $options); $writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000); try { $write = $this->db->executeBulkWrite($this->database.".".$collection, $bulk, $writeConcern); $this->_clear(); return $write; } // Check if the write concern could not be fulfilled catch (MongoDB\Driver\Exception\BulkWriteException $e) { $result = $e->getWriteResult(); if ($writeConcernError = $result->getWriteConcernError()) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("WriteConcern failure : {$writeConcernError->getMessage()}", 500); } else { show_error("WriteConcern failure", 500); } } } // Check if any general error occured. catch (MongoDB\Driver\Exception\Exception $e) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("Update of data into MongoDB failed: {$e->getMessage()}", 500); } else { show_error("Update of data into MongoDB failed", 500); } } } /** * -------------------------------------------------------------------------------- * Delete all * -------------------------------------------------------------------------------- * * Delete all documents from the passed collection based upon certain criteria * * @usage : $this->mongo_db->delete_all('foo', $data = array()); */ public function delete_all($collection = "") { if (empty($collection)) { show_error("No Mongo collection selected for delete", 500); } $options = array('limit'=>false); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->delete($this->wheres, $options); $writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000); try { $write = $this->db->executeBulkWrite($this->database.".".$collection, $bulk, $writeConcern); $this->_clear(); return $write; } // Check if the write concern could not be fulfilled catch (MongoDB\Driver\Exception\BulkWriteException $e) { $result = $e->getWriteResult(); if ($writeConcernError = $result->getWriteConcernError()) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("WriteConcern failure : {$writeConcernError->getMessage()}", 500); } else { show_error("WriteConcern failure", 500); } } } // Check if any general error occured. catch (MongoDB\Driver\Exception\Exception $e) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("Delete of data into MongoDB failed: {$e->getMessage()}", 500); } else { show_error("Delete of data into MongoDB failed", 500); } } } /** * -------------------------------------------------------------------------------- * Aggregation Operation * -------------------------------------------------------------------------------- * * Perform aggregation on mongodb collection * * @usage : $this->mongo_db->aggregate('foo', $ops = array()); */ public function aggregate($collection, $operation) { if (empty($collection)) { show_error("In order to retreive documents from MongoDB, a collection name must be passed", 500); } if (empty($operation) && !is_array($operation)) { show_error("Operation must be an array to perform aggregate.", 500); } $command = array('aggregate'=>$collection, 'pipeline'=>$operation); return $this->command($command); } /** * -------------------------------------------------------------------------------- * // Order by * -------------------------------------------------------------------------------- * * Sort the documents based on the parameters passed. To set values to descending order, * you must pass values of either -1, FALSE, 'desc', or 'DESC', else they will be * set to 1 (ASC). * * @usage : $this->mongo_db->order_by(array('foo' => 'ASC'))->get('foobar'); */ public function order_by($fields = array()) { foreach ($fields as $col => $val) { if ($val == -1 || $val === FALSE || strtolower($val) == 'desc') { $this->sorts[$col] = -1; } else { $this->sorts[$col] = 1; } } return ($this); } /** * -------------------------------------------------------------------------------- * Mongo Date * -------------------------------------------------------------------------------- * * Create new MongoDate object from current time or pass timestamp to create * mongodate. * * @usage : $this->mongo_db->date($timestamp); */ public function date($stamp = FALSE) { if ( $stamp == FALSE ) { return new MongoDB\BSON\UTCDateTime(); } else { return new MongoDB\BSON\UTCDateTime($stamp); } } /** * -------------------------------------------------------------------------------- * // Limit results * -------------------------------------------------------------------------------- * * Limit the result set to $x number of documents * * @usage : $this->mongo_db->limit($x); */ public function limit($x = 99999) { if ($x !== NULL && is_numeric($x) && $x >= 1) { $this->limit = (int) $x; } return ($this); } /** * -------------------------------------------------------------------------------- * // Offset * -------------------------------------------------------------------------------- * * Offset the result set to skip $x number of documents * * @usage : $this->mongo_db->offset($x); */ public function offset($x = 0) { if ($x !== NULL && is_numeric($x) && $x >= 1) { $this->offset = (int) $x; } return ($this); } /** * Converts document ID and returns document back. * * @param stdClass $document [Document] * @return stdClass */ private function convert_document_id($document) { if ($this->legacy_support === TRUE && isset($document['_id']) && $document['_id'] instanceof MongoDB\BSON\ObjectId) { $new_id = $document['_id']->__toString(); unset($document['_id']); $document['_id'] = new \stdClass(); $document['_id']->{'$id'} = $new_id; } return $document; } /** * -------------------------------------------------------------------------------- * // Command * -------------------------------------------------------------------------------- * * Runs a MongoDB command * * @param string : Collection name, array $query The command query * @usage : $this->mongo_db->command($collection, array('geoNear'=>'buildings', 'near'=>array(53.228482, -0.547847), 'num' => 10, 'nearSphere'=>true)); * @access public * @return object or array */ public function command($command = array()) { try{ $cursor = $this->db->executeCommand($this->database, new MongoDB\Driver\Command($command)); // Clear $this->_clear(); $returns = array(); if ($cursor instanceof MongoDB\Driver\Cursor) { $it = new \IteratorIterator($cursor); $it->rewind(); while ($doc = (array)$it->current()) { if ($this->return_as == 'object') { $returns[] = (object) $this->convert_document_id($doc); } else { $returns[] = (array) $this->convert_document_id($doc); } $it->next(); } } if ($this->return_as == 'object') { return (object)$returns; } else { return $returns; } } catch (MongoDB\Driver\Exception $e) { if(isset($this->debug) == TRUE && $this->debug == TRUE) { show_error("MongoDB query failed: {$e->getMessage()}", 500); } else { show_error("MongoDB query failed.", 500); } } } /** * -------------------------------------------------------------------------------- * //! Add indexes * -------------------------------------------------------------------------------- * * Ensure an index of the keys in a collection with optional parameters. To set values to descending order, * you must pass values of either -1, FALSE, 'desc', or 'DESC', else they will be * set to 1 (ASC). * * @usage : $this->mongo_db->add_index($collection, array('first_name' => 'ASC', 'last_name' => -1), array('unique' => TRUE)); */ public function add_index($collection = "", $keys = array(), $options = array()) { if (empty($collection)) { show_error("No Mongo collection specified to add index to", 500); } if (empty($keys) || ! is_array($keys)) { show_error("Index could not be created to MongoDB Collection because no keys were specified", 500); } foreach ($keys as $col => $val) { if($val == -1 || $val === FALSE || strtolower($val) == 'desc') { $keys[$col] = -1; } else { $keys[$col] = 1; } } $command = array(); $command['createIndexes'] = $collection; $command['indexes'] = array($keys); return $this->command($command); } /** * -------------------------------------------------------------------------------- * Remove index * -------------------------------------------------------------------------------- * * Remove an index of the keys in a collection. To set values to descending order, * you must pass values of either -1, FALSE, 'desc', or 'DESC', else they will be * set to 1 (ASC). * * @usage : $this->mongo_db->remove_index($collection, 'index_1'); */ public function remove_index($collection = "", $name = "") { if (empty($collection)) { show_error("No Mongo collection specified to remove index from", 500); } if (empty($keys)) { show_error("Index could not be removed from MongoDB Collection because no index name were specified", 500); } $command = array(); $command['dropIndexes'] = $collection; $command['index'] = $name; return $this->command($command); } /** * -------------------------------------------------------------------------------- * List indexes * -------------------------------------------------------------------------------- * * Lists all indexes in a collection. * * @usage : $this->mongo_db->list_indexes($collection); */ public function list_indexes($collection = "") { if (empty($collection)) { show_error("No Mongo collection specified to list all indexes from", 500); } $command = array(); $command['listIndexes'] = $collection; return $this->command($command); } /** * -------------------------------------------------------------------------------- * //! Switch database * -------------------------------------------------------------------------------- * * Switch from default database to a different db * * $this->mongo_db->switch_db('foobar'); */ public function switch_db($database = '') { //@todo } /** * -------------------------------------------------------------------------------- * //! Drop database * -------------------------------------------------------------------------------- * * Drop a Mongo database * @usage: $this->mongo_db->drop_db("foobar"); */ public function drop_db($database = '') { if (empty($database)) { show_error('Failed to drop MongoDB database because name is empty', 500); } $command = array(); $command['dropDatabase'] = 1; return $this->command($command); } /** * -------------------------------------------------------------------------------- * //! Drop collection * -------------------------------------------------------------------------------- * * Drop a Mongo collection * @usage: $this->mongo_db->drop_collection('bar'); */ public function drop_collection($col = '') { if (empty($col)) { show_error('Failed to drop MongoDB collection because collection name is empty', 500); } $command = array(); $command['drop'] = $col; return $this->command($command); } /** * -------------------------------------------------------------------------------- * _clear * -------------------------------------------------------------------------------- * * Resets the class variables to default settings */ private function _clear() { $this->selects = array(); $this->updates = array(); $this->wheres = array(); $this->limit = 999999; $this->offset = 0; $this->sorts = array(); } /** * -------------------------------------------------------------------------------- * Where initializer * -------------------------------------------------------------------------------- * * Prepares parameters for insertion in $wheres array(). */ private function _w($param) { if ( ! isset($this->wheres[$param])) { $this->wheres[ $param ] = array(); } } /** * -------------------------------------------------------------------------------- * Update initializer * -------------------------------------------------------------------------------- * * Prepares parameters for insertion in $updates array(). */ private function _u($method) { if ( ! isset($this->updates[$method])) { $this->updates[ $method ] = array(); } } }