`

mongoDB高效分页类

 
阅读更多

最近在研究mongodb,发现她的性能比mysql好很多,但具体快多少还没有测试过。

 
项目组最近在策划新的游戏,我们程序都开始准备相关的东西,首先是游戏的后台,由于用mongodb,所以整个框架都得重新写过,分页类也不例外。本来分页是用skip+limit的,但有一次我不知道手哪里痒了,弄了80+w数据进去,发现这种分页方法的效率骤然下降,从第一页翻到最后一页竟然要0.9s,而且只是80+w数据,效率实在太低了,因为考虑到操作日志,消费日志这些大表,百万级数据是很正常的事情,所以这样的分页是伤不起的,所以我决定改进一下分页的算法。
从网上找到资料,原来对于大数据量的分页,都不用skip+limit的,是通过改变查询规则来起到分页的效果。由于不用略过,所以无聊数据量有多大,时间复杂度的波动不大。
 
<?php
//mongoDB分页类
class Page {
var $count='';
var $size='';
var $total='';
var $last='';
var $link='';
var $url='';
var $set='';
var $page='';
var $turnto='';
var $key = '';
var $next = '';
var $prev = '';
var $lefttresult = '';
var $rightresult = '';
var $left = '';
var $right = '';
var $orderby = '';
var $lastd = '';
var $db = '';
 
//构造函数
public function __construct($last, $key, $orderby){
global $DB;
$this->db = $DB;
$this->count = $this->db->count($this->db->get_table());
$url = SITE_ROOT.strtolower(CLASS_NAME).'/'.METHOD_NAME;
$this->url = $this->url ? $this->url : $url;
$set = $set ? $set : 5;
$this->set = $set;
$size = $size ? $size : PAGE_SIZE;
$this->size = $size;
$this->last = $last;
$this->prev = $DB->get_prev($this->last);
$this->next = $DB->get_next($this->last);
$this->page = GET::UINT('page');
$this->page = $this->page ? $this->page : 1;
$this->total = @ceil($this->count / $this->size);
$this->key = $key;
$this->orderby = $orderby;
}
 
//输出分页链接
public function get_link(){
if($this->total != 1){
$this->get_first();
$this->get_prev();
$this->get_center();
$this->get_next();
$this->get_last();
$this->get_turnto();
}
if($this->link){
$this->link = $this->turnto.$this->link.'共'.number_format($this->total).'页 '.number_format($this->count).'条记录';
}
if($this->turnto){
$this->link .= '</form>';
}
return $this->link;
}
 
//获取左边显示的个数
public function get_left(){
return  $this->left = ($this->set - $this->page >= 0) ? ($this->page - 1) : $this->set;
}
 
//获取右边显示的个数
public function get_right(){
return $this->right = ($this->total - $this->page > $this->set) ? $this->set : ($this->total - $this->page);
}
 
//设置左边的结果集
public function set_left_result($left_result){
$this->leftresult = $left_result;
}
 
//设置右边的结果集
public function set_right_result($right_result){
$this->rightresult = $right_result;
}
 
//设置排序条件
public function set_orderby($orderby){
$this->orderby = $orderby;
}
 
//设置最后一页
public function set_last($last){
$this->lastd = $last;
 
//设置中间显示页码个数
public function set($set){
$this->set = $set;
}
 
//获取首页
private function get_first(){
if($this->page != 1){
if($this->total > 0){
$this->link.='<a href="'.$this->url.'" title="首页">首页</a>';
}
}
}
 
//获取上一页
private function get_prev(){
if($this->prev){
$this->link.='<a href="'.$this->url.'/page/'.($this->page - 1).'/id/'.$this->prev.'" title="上一页">上一页</a>';
}
}
 
//中间显示
private function get_center(){
$start = ($this->page - $this->set) <= 0 ? 1 : ($this->page - $this->set);  
$end = ($this->page + $this->set + 1 >= $this->total) ? $this->total + 1 : ($this->page + $this->set + 1);
 
$ii = $this->left;
$iii = 0;
//显示左边的
for($i = $start; $i < $end; $i++, $ii--, $iii++){
if($this->page == $i){
$this->link.='<a style="color:#06F">'.$i.'</a>';
}else{
$the_id = $ii * $this->size - 1;
if($the_id > 0){
$this->link.='<a href="'.$this->url.'/page/'.$i.'/id/'.$this->leftresult[$the_id][$this->key].'" title="第'.$i.'页">'.$i.'</a>';
}else{
$the_id = ($iii - $this->left) * $this->size;
$this->link.='<a href="'.$this->url.'/page/'.$i.'/id/'.$this->rightresult[$the_id][$this->key].'" title="第'.$i.'页">'.$i.'</a>';
}
}
}
}
 
//获取下一页
private function get_next(){
if($this->next){
$this->link.='<a href="'.$this->url.'/page/'.($this->page + 1).'/id/'.$this->next.'" title="下一页">下一页</a>';
}
}
 
//获取尾页
private function get_last(){
if($this->page != $this->total){
$this->link.='<a href="'.$this->url.'/page/'.$this->total.'/id/'.$this->lastd.'" title="尾页">尾页</a>';
}
}
 
//跳转到
private function get_turnto(){
$this->turnto = '<form action="" method="get" onsubmit="window.location=\''.$this->url.'/search/\'+this.p.value+\''.'\';return false;">转到第 <input type="text" name="p" style="width:25px;text-align:center"> 页';
}
 
//求反
public function nor_orderby(){
foreach($this->orderby as $key => $order){
if($order==-1){
$orderby[$key] = 1;
}else{
$orderby[$key] = -1;
}
}
return $orderby;
}
 
//设置key
public function set_key($key){
$this->key = $key;
}
 
//分页操作
public function show(){
$this->set_key($this->key);
$this->set_orderby($this->orderby);
$left = $this->get_left();
$right = $this->get_right();
$leftresult = $this->db->get_left($left, $this->last);
$rightresult = $this->db->get_right($right, $this->last);
$this->set_left_result($leftresult);
$this->set_right_result($rightresult);
$last = $this->db->get_last();
$this->set_last($last); 
return $this->get_link();
}
}
/*      调用例子
global $DB;
$lastid = GET::UINT('id');
$table = 'log';
$key = '_id';
$orderby = array($key => -1);
 
$DB->set_table($table);
$DB->set_key($key);
$DB->set_orderby($orderby);
 
$log = $DB->page_query($lastid);
 
$page = new Page($lastid, $key, $orderby);
$pager = $page->show();
*/
?>
附上对应的mongodb类
<?php 
 
//MongoDB操作类
class DB 
{
 
private $CI;
private $config_file = 'MongoDB';
 
private $connection;
private $db;
private $connection_string;
 
private $collection = '';
private $host;
private $port;
private $user;
private $pass;
private $dbname;
private $key;
private $persist;
private $persist_key;
 
private $selects = array();
private $wheres = array();
private $sorts = array();
private $page_sorts = array();
 
private $limit = 999999;
private $offset = 0;
 
 
/**
 *--------------------------------------------------------------------------------
 *CONSTRUCTOR
 *--------------------------------------------------------------------------------
 *
 *Automatically check if the Mongo PECL extension has been installed/enabled.
 *Generate the connection string and establish a connection to the MongoDB.
 */
 
public function __construct($MONGODB_CONFIG)
{
if(!class_exists('Mongo'))
{
show_error("The MongoDB PECL extension has not been installed or enabled", 500);
}
$this->connection_string($MONGODB_CONFIG);
$this->connect();
}
 
 
 
/**
 *--------------------------------------------------------------------------------
 *Switch_db
 *--------------------------------------------------------------------------------
 *
 *Switch from default database to a different db
 */
 
public function switch_db($database = '')
{
if(empty($database))
{
show_error("To switch MongoDB databases, a new database name must be specified", 500);
}
$this->dbname = $database;
try
{
$this->db = $this->connection->{$this->dbname};
return(TRUE);
}
catch(Exception $e)
{
show_error("Unable to switch Mongo Databases: {$e->getMessage()}", 500);
}
}
 
/**
 *--------------------------------------------------------------------------------
 *SELECT FIELDS
 *--------------------------------------------------------------------------------
 *
 *Determine which fields to include OR which to exclude during the query process.
 *Currently, including and excluding at the same time is not available, so the 
 *$includes array will take precedence over the $excludes array.  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 $col)
 {
 $this->selects[$col] = 1;
 }
 }
 else
 {
 foreach($excludes as $col)
 {
 $this->selects[$col] = 0;
 }
 }
 return($this);
}
 
/**
 *--------------------------------------------------------------------------------
 *WHERE PARAMETERS
 *--------------------------------------------------------------------------------
 *
 *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 = array())
 {
 foreach($wheres as $wh => $val)
 {
 $this->wheres[$wh] = $val;
 }
 return($this);
 }
 
/**
 *--------------------------------------------------------------------------------
 *WHERE_IN PARAMETERS
 *--------------------------------------------------------------------------------
 *
 *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())
 {
 $this->where_init($field);
 $this->wheres[$field]['$in'] = $in;
 return($this);
 }
 
/**
 *--------------------------------------------------------------------------------
 *WHERE_NOT_IN PARAMETERS
 *--------------------------------------------------------------------------------
 *
 *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())
 {
 $this->where_init($field);
 $this->wheres[$field]['$nin'] = $in;
 return($this);
 }
 
/**
 *--------------------------------------------------------------------------------
 *WHERE GREATER THAN PARAMETERS
 *--------------------------------------------------------------------------------
 *
 *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)
 {
 $this->where_init($field);
 $this->wheres[$field]['$gt'] = $x;
 return($this);
 }
 
/**
 *--------------------------------------------------------------------------------
 *WHERE GREATER THAN OR EQUAL TO PARAMETERS
 *--------------------------------------------------------------------------------
 *
 *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)
 {
 $this->where_init($field);
 $this->wheres[$field]['$gte'] = $x;
 return($this);
 }
 
/**
 *--------------------------------------------------------------------------------
 *WHERE LESS THAN PARAMETERS
 *--------------------------------------------------------------------------------
 *
 *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)
 {
 $this->where_init($field);
 $this->wheres[$field]['$lt'] = $x;
 return($this);
 }
 
/**
 *--------------------------------------------------------------------------------
 *WHERE LESS THAN OR EQUAL TO PARAMETERS
 *--------------------------------------------------------------------------------
 *
 *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)
 {
 $this->where_init($field);
 $this->wheres[$field]['$lte'] = $x;
 return($this);
 }
 
/**
 *--------------------------------------------------------------------------------
 *WHERE BETWEEN PARAMETERS
 *--------------------------------------------------------------------------------
 *
 *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)
 {
 $this->where_init($field);
 $this->wheres[$field]['$gte'] = $x;
 $this->wheres[$field]['$lte'] = $y;
 return($this);
 }
 
/**
 *--------------------------------------------------------------------------------
 *WHERE BETWEEN AND NOT EQUAL TO PARAMETERS
 *--------------------------------------------------------------------------------
 *
 *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)
 {
 $this->where_init($field);
 $this->wheres[$field]['$gt'] = $x;
 $this->wheres[$field]['$lt'] = $y;
 return($this);
 }
 
/**
 *--------------------------------------------------------------------------------
 *WHERE NOT EQUAL TO PARAMETERS
 *--------------------------------------------------------------------------------
 *
 *Get the documents where the value of a $field is not equal to $x
 *
 *@usage = $this->mongo_db->where_between('foo', 20, 30);
 */
 
 public function where_ne($field = "", $x)
 {
 $this->where_init($field);
 $this->wheres[$field]['$ne'] = $x;
 return($this);
 }
 
 /**
 *--------------------------------------------------------------------------------
 *WHERE OR
 *--------------------------------------------------------------------------------
 *
 *Get the documents where the value of a $field is in one or more values
 *
 *@usage = $this->mongo_db->where_or('foo', array( 'foo', 'bar', 'blegh' );
 */
 
 public function where_or($field = "", $values)
 {
 $this->where_init($field);
 $this->wheres[$field]['$or'] = $values;
 return($this);
 }
 
/**
 *--------------------------------------------------------------------------------
 *WHERE AND
 *--------------------------------------------------------------------------------
 *
 *Get the documents where the elements match the specified values
 *
 *@usage = $this->mongo_db->where_and( array ( 'foo' => 1, 'b' => 'someexample' );
 */
 
 public function where_and( $elements_values = array() ) {
 foreach ( $elements_values as $element => $val ) {
 $this->wheres[$element] = $val;
 }
 return($this);
 }
 
 /**
 *--------------------------------------------------------------------------------
 *WHERE MOD
 *--------------------------------------------------------------------------------
 *
 *Get the documents where $field % $mod = $result
 *
 *@usage = $this->mongo_db->where_mod( 'foo', 10, 1 );
 */
 
 public function where_mod( $field, $num, $result ) {
 $this->where_init($field);
 $this->wheres[$field]['$mod'] = array ( $num, $result );
 return($this);
 }
 
/**
*--------------------------------------------------------------------------------
*Where size
*--------------------------------------------------------------------------------
*
*Get the documents where the size of a field is in a given $size int
*
*@usage : $this->mongo_db->where_size('foo', 1)->get('foobar');
*/
 
public function where_size($field = "", $size = "")
{
$this->_where_init($field);
$this->wheres[$field]['$size'] = $size;
return ($this);
}
 
/**
 *--------------------------------------------------------------------------------
 *LIKE PARAMETERS
 *--------------------------------------------------------------------------------
 *
 *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)
 {
 $field = (string) trim($field);
 $this->where_init($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);
 }
 
/**
 *--------------------------------------------------------------------------------
 *ORDER BY PARAMETERS
 *--------------------------------------------------------------------------------
 *
 *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->where_between('foo', 20, 30);
 */
 
 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);
 }
 
/**
 *--------------------------------------------------------------------------------
 *LIMIT DOCUMENTS
 *--------------------------------------------------------------------------------
 *
 *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 DOCUMENTS
 *--------------------------------------------------------------------------------
 *
 *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);
 }
 
/**
 *--------------------------------------------------------------------------------
 *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(), $limit = 99999)
 {
 return($this->where($where)->limit($limit)->get($collection));
 }
 
/**
 *--------------------------------------------------------------------------------
 *GET
 *--------------------------------------------------------------------------------
 *
 *Get the documents based upon the passed parameters
 *
 *@usage = $this->mongo_db->get('foo', array('bar' => 'something'));
 */
 
 public function get($collection = "")
 {
 if(empty($collection))
 {
 show_error("In order to retreive documents from MongoDB, a collection name must be passed", 500);
 }
 $results = array();
 $documents = $this->db->{$collection}->find($this->wheres, $this->selects)->limit((int) $this->limit)->skip((int) $this->offset)->sort($this->sorts);
 
 $returns = array();
 
 foreach($documents as $doc):
 $returns[] = $doc;
 endforeach;
$this->clear();
 return($returns);
 
 }
 
/**
 *--------------------------------------------------------------------------------
 *COUNT
 *--------------------------------------------------------------------------------
 *
 *Count the documents based upon the passed parameters
 *
 *@usage = $this->mongo_db->get('foo');
 */
 
 public function count($collection = "")
 {
 if(empty($collection))
 {
 show_error("In order to retreive a count of documents from MongoDB, a collection name must be passed", 500);
 }
 $count = $this->db->{$collection}->find($this->wheres)->limit((int) $this->limit)->skip((int) $this->offset)->count();
 $this->clear();
 return($count);
 }
 
/**
 * 自增ID实现
 * return insert_id
 */
private function insert_inc($table)
$update = array('$inc'=>array('id'=>1));
$query = array('table'=>$table);
$command = array(
'findandmodify'=>'_increase', 
'update'=>$update,
'query'=>$query, 
'new'=>true, 
'upsert'=>true
);
$id = $this->db->command($command);
return $id['value']['id'];
}
 
/**
 *--------------------------------------------------------------------------------
 *INSERT
 *--------------------------------------------------------------------------------
 *
 *Insert a new document into the passed collection
 *
 *@usage = $this->mongo_db->insert('foo', $data = array());
 */
 
 public function insert($collection = "", $data = array()) {
 if(empty($collection))
 {
 show_error("No Mongo collection selected to insert into", 500);
 }
 
 if(count($data) == 0 || !is_array($data))
 {
 show_error("Nothing to insert into Mongo collection or insert is not an array", 500);
 }
 
 try
 {
$inc = $this->insert_inc($collection);
$data['_id'] = $inc;
 $result = $this->db->{$collection}->insert($data, array('fsync' => TRUE));
 if($result['ok'] || $result){
return true;
}
else{
return false;
}
 }
 catch(MongoCursorException $e)
 {
 show_error("Insert of data into MongoDB failed: {$e->getMessage()}", 500);
 }
 
 }
 
/**
 *--------------------------------------------------------------------------------
 *UPDATE
 *--------------------------------------------------------------------------------
 *
 *Update a document into the passed collection
 *
 *@usage = $this->mongo_db->update('foo', $data = array());
 */
 
 public function update($collection = "", $data = array(), $flage = false)
 {
 if(empty($collection))
 {
 show_error("No Mongo collection selected to update", 500);
}
 if(count($data) == 0 || !is_array($data))
 {
 show_error("Nothing to update in Mongo collection or update is not an array", 500);
}
unset($data['_id']);
if($flage){
$arr = $this->wheres;
unset($arr['_id']);
if(is_array($arr)){
foreach($arr as $key => $w){
unset($data[$key]);
}
}
}
try
 {
 $res = $this->db->{$collection}->update($this->wheres, array('$set' => $data), array('fsync' => TRUE, 'multiple' => FALSE));
$this->clear();
return $res;
 }  
 catch(MongoCursorException $e)
 {
 show_error("Update of data into MongoDB failed: {$e->getMessage()}", 500);
 }
 
 }
 
/**
 *--------------------------------------------------------------------------------
 *UPDATE_ALL
 *--------------------------------------------------------------------------------
 *
 *Insert a new document into the passed collection
 *
 *@usage = $this->mongo_db->update_all('foo', $data = array());
 */
 
 public function update_all($collection = "", $data = array()) {
 if(empty($collection))
 {
 show_error("No Mongo collection selected to update", 500);
 }
 
 if(count($data) == 0 || !is_array($data))
 {
 show_error("Nothing to update in Mongo collection or update is not an array", 500);
 }
 
 try
 {
 $this->db->{$collection}->update($this->wheres, array('$set' => $data), array('fsync' => TRUE, 'multiple' => TRUE));
$this->clear();
 return(TRUE);
 
 catch(MongoCursorException $e)
 {
 show_error("Update of data into MongoDB failed: {$e->getMessage()}", 500);
 }
 
 }
 
 /**
 *--------------------------------------------------------------------------------
 *DELETE
 *--------------------------------------------------------------------------------
 *
 *delete document from the passed collection based upon certain criteria
 *
 *@usage = $this->mongo_db->delete('foo', $data = array());
 */
 
 public function delete($collection, $where)
 {
 if(empty($collection))
 {
 show_error("No Mongo collection selected to delete from", 500);
 }
if(!$where){
show_error("No data input to delete", 500);
}
 try
 {
$this->wheres = $where;
 $this->db->{$collection}->remove($this->wheres);
$this->clear();
 return(TRUE);
 }
 catch(MongoCursorException $e)
 {
 show_error("Delete of data into MongoDB failed: {$e->getMessage()}", 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 to delete from", 500);
  }
 
 try
 {
 $this->db->{$collection}->remove($this->wheres, array('fsync' => TRUE, 'justOne' => FALSE));
$this->clear();
 return(TRUE);
 }
 catch(MongoCursorException $e)
 {
 show_error("Delete of data into MongoDB failed: {$e->getMessage()}", 500);
 }
 
  }
 
/**
 *--------------------------------------------------------------------------------
 *ADD_INDEX
 *--------------------------------------------------------------------------------
 *
 *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;
 }
 }
 
 if($this->db->{$collection}->ensureIndex($keys, $options) == TRUE)
 {
 $this->clear();
 return($this);
 }
 else
 {
 show_error("An error occured when trying to add an index to MongoDB Collection", 500);
}
}
 
 
 
/**
 *--------------------------------------------------------------------------------
 *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, array('first_name' => 'ASC', 'last_name' => -1));
 */
 
public function remove_index($collection = "", $keys = array())
{
if(empty($collection))
{
 show_error("No Mongo collection specified to remove index from", 500);
 }
 
 if(empty($keys) || !is_array($keys))
 {
 show_error("Index could not be removed from MongoDB Collection because no keys were specified", 500);
 }
 
 if($this->db->{$collection}->deleteIndex($keys, $options) == TRUE)
 {
 $this->clear();
 return($this);
 }
 else
 {
 show_error("An error occured when trying to remove an index from MongoDB Collection", 500);
}
}
 
/**
 *--------------------------------------------------------------------------------
 *REMOVE_ALL_INDEXES
 *--------------------------------------------------------------------------------
 *
 *Remove all indexes from a collection.
 *
 *@usage = $this->mongo_db->remove_all_index($collection);
 */
 
public function remove_all_indexes($collection = "") {
if(empty($collection))
{
 show_error("No Mongo collection specified to remove all indexes from", 500);
 }
 
 $this->db->{$collection}->deleteIndexes();
 $this->clear();
 return($this);
}
 
/**
 *--------------------------------------------------------------------------------
 *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 remove all indexes from", 500);
 }
 return($this->db->{$collection}->getIndexInfo());
}
 
/**
 *--------------------------------------------------------------------------------
 *DROP COLLECTION
 *--------------------------------------------------------------------------------
 *
 *Removes the specified collection from the database.  Be careful because this
 *  can have some very large issues in production!
 */
 
 public function drop_collection($collection = "")
 {
   if(empty($collection))
 {
     show_error("No Mongo collection specified to drop from database", 500);
   }
   $this->db->{$collection}->drop();
   return TRUE;
 }
 
 
/**
 *--------------------------------------------------------------------------------
 *CONNECT TO MONGODB
 *--------------------------------------------------------------------------------
 *
 *Establish a connection to MongoDB using the connection string generated in
 *the connection_string() method.  If 'mongo_persist_key' was set to true in the
 *config file, establish a persistent connection.  We allow for only the 'persist'
 *option to be set because we want to establish a connection immediately.
 */
 
private function connect() {
$options = array();
if($this->persist === TRUE)
{
$options['persist'] = isset($this->persist_key) && !empty($this->persist_key) ? $this->persist_key : 'ci_mongo_persist';
}
 
try
{
$this->connection = new Mongo($this->connection_string, $options);
$this->db = $this->connection->{$this->dbname};
return($this);
catch(MongoConnectionException $e)
{
show_error("Unable to connect to MongoDB: {$e->getMessage()}", 500);
}
}
 
/**
 *--------------------------------------------------------------------------------
 *BUILD CONNECTION STRING
 *--------------------------------------------------------------------------------
 *
 *Build the connection string from the config file.
 */
 
private function connection_string($MONGODB_CONFIG) 
{
 
$this->host = trim($MONGODB_CONFIG['HOST']);
$this->port = trim($MONGODB_CONFIG['PORT']);
$this->user = trim($MONGODB_CONFIG['USER']);
$this->pass = trim($MONGODB_CONFIG['PWD']);
$this->dbname = trim($MONGODB_CONFIG['DATABASE']);
$this->persist = trim($MONGODB_CONFIG['PERSIST']);
$this->persist_key = trim($MONGODB_CONFIG['PERSIST_KEY']);
 
$connection_string = "mongodb://";
 
if(empty($this->host))
{
show_error("The Host must be set to connect to MongoDB", 500);
}
 
if(empty($this->dbname))
{
show_error("The Database must be set to connect to MongoDB", 500);
}
 
if(!empty($this->user) && !empty($this->pass))
{
$connection_string .= "{$this->user}:{$this->pass}@";
}
 
if(isset($this->port) && !empty($this->port))
{
$connection_string .= "{$this->host}:{$this->port}/{$this->dbname}";
}
else
{
$connection_string .= "{$this->host}";
}
 
$this->connection_string = trim($connection_string);
}
 
/**
 *--------------------------------------------------------------------------------
 *CLEAR
 *--------------------------------------------------------------------------------
 *
 *Resets the class variables to default settings
 */
 
private function clear()
{
$this->selects = array();
$this->wheres = array();
$this->limit = NULL;
$this->offset = NULL;
$this->sorts = array();
}
 
/**
 *--------------------------------------------------------------------------------
 *WHERE INITIALIZER
 *--------------------------------------------------------------------------------
 *
 *Prepares parameters for insertion in $wheres array().
 */
 
private function where_init($param) 
{
if(!isset($this->wheres[$param]))
{
$this->wheres[$param] = array();
  }
}
 
/**
 *--------------------------------------------------------------------------------
 *设置表
 *--------------------------------------------------------------------------------
 *  参数:
 *  $table 表名
 */
public function set_table($table){
$this->collection = $table;
}
 
/**
 *--------------------------------------------------------------------------------
 *获取表名
 *--------------------------------------------------------------------------------
 */
public function get_table(){
return $this->collection;
}
 
/**
 *--------------------------------------------------------------------------------
 *设置表排序
 *--------------------------------------------------------------------------------
 *  参数:
 *  $orderby 排序
 */
public function set_orderby($orderby){
$this->page_sorts = $orderby;
}
 
 
/**
 *--------------------------------------------------------------------------------
 *获取左边结果集
 *--------------------------------------------------------------------------------
 *  参数:
 *  $left 左边显示的个数
 *  $last 定位当前页的值
 *  $size 页面大小
 */
public function get_left($left, $last, $size = PAGE_SIZE){
if($last){
$order = $this->nor_orderby();
if($this->page_sorts[$this->key] == -1){
$this->where_gt($this->key, $last);
} else {
 $this->where_lt($this->key, $last);
}
return $this->limit($left * $size)->order_by($order)->get($this->collection); 
}
}
 
 
/**
 *--------------------------------------------------------------------------------
 *获取右边结果集
 *--------------------------------------------------------------------------------
 *  参数:
 *  $right 右边显示的个数
 *  $last 定位当前页的值
 *  $size 页面大小
 */
public function get_right($right, $last, $size = PAGE_SIZE){
if($last){
if($this->page_sorts[$this->key] == -1){
$this->where_lte($this->key, $last);
} else {
$this->where_gte($this->key, $last);
}
}
return $this->limit($right * $size + 1)->order_by($this->page_sorts)->get($this->collection);
}
 
/**
 *--------------------------------------------------------------------------------
 *设置key
 *--------------------------------------------------------------------------------
 *  参数:
 *  $key 设置索引主键
 */
public function set_key($key){
$this->key = $key;
}
 
/**
 *--------------------------------------------------------------------------------
 *求反
 *-------------------------------------------------------------------------------- 
 */
private function nor_orderby(){
foreach($this->page_sorts as $key => $order){
if($order == -1){
$orderby[$key] = 1;
}else{
$orderby[$key] = -1;
}
}
return $orderby;
}
 
/**
 *--------------------------------------------------------------------------------
 *获取上一页的值
 *-------------------------------------------------------------------------------- 
 *  参数:
 *  $last 定位当前页的值
 *  $size 页面大小
 */
public function get_prev($last, $size = PAGE_SIZE){
if($last){
if($this->page_sorts[$this->key] == 1){
$this->where_lt($this->key,$last)->order_by(array($this->key => -1));
} else {
$this->where_gt($this->key,$last)->order_by(array($this->key => 1));
}
$result = $this->limit($size)->get($this->collection);
}
return $result[$size - 1][$this->key];
}
 
 /**
 *--------------------------------------------------------------------------------
 *获取下一页的值
 *-------------------------------------------------------------------------------- 
 *  参数:
 *  $last 定位当前页的值
 *  $size 页面大小
 */
public function get_next($last, $size = PAGE_SIZE){
if($last){
if($this->page_sorts[$this->key] == 1){
$this->where_gte($this->key,$last);
} else {
$this->where_lte($this->key,$last);
}
}
$result = $this->limit($size+1)->order_by($this->page_sorts)->get($this->collection);
return $result[$size][$this->key];
}
 
/**
 *--------------------------------------------------------------------------------
 *获取最后一页的值
 *-------------------------------------------------------------------------------- 
 *  参数:
 *  $size 页面大小
 */
public function get_last($size = PAGE_SIZE){
$res = $this->count($this->collection) % $size;
$order = $this->nor_orderby();
if($res > 0){
$result = $this->limit($res)->order_by($order)->get($this->collection);
return $result[$res - 1][$this->key];
}else{
$result = $this->limit($size)->order_by($order)->get($this->collection);
return $result[$size - 1][$this->key];
}
}
 
/**
 *--------------------------------------------------------------------------------
 *分页查询
 *-------------------------------------------------------------------------------- 
 *  参数:
 *  $last 定位当前页的值
 *  $size 页面大小
 */
public function page_query($last, $size = PAGE_SIZE){
if($last){
if($this->page_sorts[$this->key]==1){
$this->where_gte($this->key,$last);
} else {
$this->where_lte($this->key,$last);
}
}
return $this->limit($size)->order_by($this->page_sorts)->get($this->collection);
 
/**
 * 批量执行代码_插入
 * @param String $collection
 * @param 二维数组 $code 
 */
public function execute_insert($collection,$code){
//将二维数组分成js格式
$strcode='';
foreach($code as $k=>$v){
foreach($v as $kk=>$vv){
$strcode.='db.getCollection("'.$collection.'").insert({ "'.$kk.'":"'.$vv.'" });';
}
}
//retrun array([ok]=>1);
return $this->db->execute($code);
}
 
 
}
?>
 
 
 
 
经过优化之后,89w数据直接翻到最后一页只用了0.002s,效率明显提高,不过和rockmongo的效率还有很大差距,rockmongo的分页思路和我的有点不一样。
分享到:
评论

相关推荐

    高效mongodb的php分页类(不使用skip).zip

    介绍了高效mongodb的php分页类,并且没有使用mongodb的skip来实现分页,需要的朋友可以参考下,mongodb分页skip limit分页要先查出所有结果再去跳过,这样如果查询页面越往后效率越低。 如果能够通过查询条件查出...

    高效mongodb的php分页类(不使用skip)

    主要介绍了高效mongodb的php分页类,并且没有使用mongodb的skip来实现分页,需要的朋友可以参考下

    minquery:支持高效分页的MongoDB mgo查询(光标继续列出我们停下来的文档)

    最小查询 支持高效分页的MongoDB / mgo查询(游标可在我们停下的地方继续列出文档)。 注意:仅MongoDB 3.2和更高版本支持此软件包使用的功能。 注意#2: minquery 使用gopkg.in/mgo.v2驱动程序,该驱动程序已经很...

    NodeJS完整指南:掌握Node JS和Deno.js,使用Node.js构建REST API,GraphQL API,添加身份验证,使用MongoDB,SQL等!

    Deno等)课程大纲入门JavaScript刷新器Node.js基础高效发展使用Express.js 模板引擎模型视图控制器(MVC) 先进的路线和模型节点+ SQL(MySQL) 使用续集节点+ NoSQL(MongoDB) 使用猫鼬会话和Cookie 认证方式发送...

    express-startapp:具有Docker + Docker-compose,CircleCI,MongoDB + Mongoose,Redis,S3,实用程序和动态配置的Express Server

    高效的API休息示例 本地环境:npm运行本地或npm运行本地双赢(适用于Windows) 开发环境:npm run dev 生产环境:npm启动 根据命令的不同,如何在config.js中获取配置参数 邮递员: : 特征: Docker + Docker...

    PHP框架DoitPHP v1.3.zip

    六、丰富的数据库驱动,支持MYSQL、POSTGRESQL、ORACLE、SQLITE、MSSQL、MONGODB等数据库。   DoitPHP 1.3 更新日志 一、核心类 1. Model class 2. Controller class 3、Log class 4...

    晨曦小竹常用工具集

    《晨曦小竹常用工具集》,多年工作积累而成,涵盖DawnUtility[常规]、DBUtility[数据]、FileUtility[文件]、FormUtility[视窗]、PagerUtility[分页]、VerifyUtility[验证]、WebUtility[WEB相关]等等,所有工具方法等...

    打造Node.js全栈开发工程师

    并会讲解一个基于bootstrap+express+mongodb实现一个包括用户管理、文章管理、查看留言、分页查询、 搜索、文件上传、pv留言统计等功能完整的博客系统。使用了express的路由、ejs模板和serve-favicon、 morgan、...

    PhP框架DoitPHP v1.5 MySql版.zip

    六、丰富的数据库驱动,支持MYSQL、POSTGRESQL、ORACLE、SQLITE、MSSQL、MONGODB等数据库。 DoitPHP v1.5 更新日志 1、对视图文件格式为php和html两种情况的操作进行整合。可使用统一的视图类方法进行视图文件的...

    PHP框架DoitPHP v1.5 SAE版.zip

    六、丰富的数据库驱动,支持MYSQL、POSTGRESQL、ORACLE、SQLITE、MSSQL、MONGODB等数据库。  DoitPHP v1.5 更新日志 1、对视图文件格式为php和html两种情况的操作进行整合。可使用统一的视图类方法进行视图文件的...

    DoitPHP 框架

    ...简而言之:DoitPHP运行高效,易学易用,易于扩展。换而言之:DoitPHP运行高效而不失功能强大,操作灵活而又能扩展...六、丰富的数据库驱动,支持MYSQL、POSTGRESQL、ORACLE、SQLITE、MSSQL、MONGODB、REDIS等数据库。

    DoitPHP 1.0

    运行高效而不失功能强大,操作灵活而又能扩展自如。...并在操作和功能设计上进行了微创新: 一、DoitPHP的辅助开发工具...六、丰富的数据库驱动,支持MYSQL、POSTGRESQL、ORACLE、SQLITE、MSSQL、MONGODB等数据库。

    数据库SQL、NoSQL之小感悟

    遇到1000万数据表  近遇到一个问题,是单表数据过1000万的存储...  常用的数据库产品对分页都是有一些支持的,SQL语句肯定是OK的,同样的问题在于如何高效。因为分页查询大的问题在于查询越往后的数据越慢,因为要扫

    Mycat-server-1.6-RELEASE源码

    支持数据的多片自动路由与聚合,支持sum,count,max等常用的聚合函数,支持跨库分页。 支持单库内部任意join,支持跨库2表join,甚至基于caltlet的多表join。 支持通过全局表,ER关系的分片策略,实现了高效的多表join...

    这是一款特别适用于中小企业应用的JavaEE快速开发框架.zip

    它是居于Spring容器之上,封装了DAO(含Hibernate和MongoDB)操作、多模块统一管理、统一配置管理、统一日志管理等优雅的工程管理开发模型,并提供大量工具包、Json操作、分页辅助工具。 开发工具在软件开发生命...

Global site tag (gtag.js) - Google Analytics