array(..), field2 => array(...) ... private $_results = array();//field => [1|0] private $_sort = array();//field => [1|-1] private $_offset = -1; private $_limit = 0; private $_conds = array();//field1 => array( '$lt' => value1, .. ) private $_noPk = false; private $_hints = array(); /** * 构造查询 * * @param Mongo $mongo MongoDB连接 * @param string $db 数据库 * @param string $collection 集合 */ function __construct(RMongo $mongo, $db, $collection) { $this->_dbName = $db; $this->_collectionName = $collection; $this->_db = $mongo->selectDB($this->_dbName); $this->_collection = $mongo->selectCollection($this->_dbName, $this->_collectionName); } /** * 指定属性值 * * @param string|array $nameOrAttrs 属性名或一组属性值 * @param string $value 属性值 * @return RQuery */ function attr($nameOrAttrs, $value = null) { if (!is_array($nameOrAttrs)) { $nameOrAttrs = array( $nameOrAttrs => $value ); } foreach ($nameOrAttrs as $attr => $value) { if ($attr == "_id" && (!is_object($value) || !($value instanceof MongoId)) && strlen($attr) == 24) { $value = new MongoId($value); } if (!isset($this->_attrs[$attr])) { $this->_attrs[$attr] = array(); } if (is_array($value)) { $this->_attrs[$attr] = array_merge($this->_attrs[$attr], array($value)); } else { $this->_attrs[$attr][] = $value; } } return $this; } /** * 指定返回的结果属性。在当前的mongo版本中(<1.4.x),不能混合使用result()和exclude() * * @param string $attr1 第一个属性 * @param ... * @return RQuery */ function result($attr1 = null) { foreach (func_get_args() as $arg) { if ($arg) { if (is_array($arg)) { foreach ($arg as $v) { $this->_results[$v] = 1; } } else if (strstr($arg, ",")) { foreach (preg_split("/\s*,\s*/", $arg) as $attr) { $this->_results[$attr] = 1; } } else { $this->_results[$arg] = 1; } } } return $this; } /** * 指定返回的结果中要排除的属性 * * @param string $attr1 第一个属性 * @param ... * @return RQuery */ function exclude($attr1 = null) { foreach (func_get_args() as $arg) { if ($arg) { if (strstr($arg, ",")) { foreach (preg_split("/\s*,\s*/", $arg) as $attr) { $this->_results[$attr] = 0; } } else { $this->_results[$arg] = 0; } } } return $this; } /** * 设置正排序条件 * * @param string $attr 需要排序的属性 * @return RQuery */ function asc($attr = "_id") { $this->_sort[$attr] = 1; return $this; } /** * 设置倒排序条件 * * @param string $attr 需要排序的属性 * @return RQuery */ function desc($attr = "_id") { $this->_sort[$attr] = -1; return $this; } /** * 设置记录开始的位置 * * @param integer $offset 开始位置 * @return RQuery */ function offset($offset) { $this->_offset = intval($offset); return $this; } /** * 设置需要查询的记录行数 * * @param integer $size 行数 * @return RQuery */ function limit($size) { $this->_limit = intval($size); return $this; } /** * 增加查询条件 * * @param array $cond 查询条件 * @return RQuery */ function cond(array $cond) { foreach ($cond as $key => $value) { $this->_conds[$key] = $value; } return $this; } /** * 添加操作符 * * @param string $attr 属性名 * @param string $operator 操作符,比如$gt, $lt ... * @param mixed $value 操作符对应的值 * @return RQuery */ function operator($attr, $operator, $value) { if (!isset($this->_conds[$attr])) { $this->_conds[$attr] = array(); } $this->_conds[$attr][$operator] = $value; return $this; } function gt($attr, $value) { return $this->operator($attr, '$gt', $value); } function lt($attr, $value) { return $this->operator($attr, '$lt', $value); } function gte($attr, $value) { return $this->operator($attr, '$gte', $value); } function lte($attr, $value) { return $this->operator($attr, '$lte', $value); } /** * 设置不等于(!=)条件 * * @param string $attr 属性名 * @param mixed $value 和属性比较的值 * @return RQuery */ function ne($attr, $value) { return $this->operator($attr, '$ne', $value); } function in($attr, array $values) { return $this->operator($attr, '$in', $values); } function nin($attr, array $values) { return $this->operator($attr, '$nin', $values); } function mod($attr, $value) { return $this->operator($attr, '$mod', $value); } function all($attr, $value) { return $this->operator($attr, '$all', $value); } function contains($attr, $value) { return $this->all($attr, '$all', $value); } /** * 限定集合属性的尺寸 * * @param string $attr 属性名 * @param integer $size 限制的尺寸 * @return RQuery */ function size($attr, $size) { return $this->operator($attr, '$size', intval($size)); } function exists($attr, $bool = true) { return $this->operator($attr, '$exists', $bool); } function type($attr, $type) { return $this->operator($attr, '$type', intval($type)); } function match($attr, $regexp) { return $this->attr($attr, new MongoRegex($regexp)); } /** * 分割一个是集合(相当于PHP中的索引数组)的属性值 * * @param string $attr 属性名 * @param integer $subOffset 开始位置 * @param integer $subLimit 要取出的条数 * @return RQuery */ function slice($attr, $subOffset, $subLimit) { $this->_results[$attr]['$slice'] = array( intval($subOffset), intval($subLimit) ); return $this; } /** * 使用函数。如果数据较多话,将会非常慢。 * * @param string $func Javascript函数 * @return RQuery */ function func($func) { $this->_conds['$where'] = $func; return $this; } /** * 设置否是不返回主键(_id) * * @param unknown_type $returnPk * @return RQuery */ function noPk($noPk = true) { $this->_noPk = $noPk; return $this; } /** * 设置查询的主键值 * * @param string $pk1 主键1 * @param string ... * @return RQuery */ function id($pk1) { foreach (func_get_args() as $arg) { $this->attr("_id", $arg); } return $this; } function copy() { exit(__METHOD__ . "() to be implemented"); } /** * 现有查询条件的组合 * * @return array */ function criteria() { $attrs = $this->_attrs; foreach ($this->_attrs as $attr => $values) { if (!empty($values)) { if (count($values) == 1) { $attrs[$attr] = $values[0]; } else { $attrs[$attr]['$in'] = $values; } } } foreach ($this->_conds as $key => $value) { $attrs[$key] = $value; } return $attrs; } /** * add hints for query * * @param unknown_type $hint * @return RQuery */ function hint($hint) { $this->_hints[] = $hint; return $this; } /** * 取得当前查询的游标 * * @return MongoCursor */ function cursor() { $cursor = $this->_collection->find($this->criteria(), $this->_results); if ($this->_offset >= 0) { $cursor->skip($this->_offset); } if ($this->_limit > 0) { $cursor->limit($this->_limit); } if ($this->_sort) { $cursor->sort($this->_sort); } if (!empty($this->_hints)) { foreach ($this->_hints as $hint) { $cursor->hint($hint); } } return $cursor; } /** * 查找一行数据,并以一个对象的形式返回 * * @param string $id 主键_id值 * @return RObject */ function find($id = null) { if (!is_null($id)) { $this->id($id); } $row = $this->findOne(); if (empty($row)) { return null; } import("@.RObject"); $obj = new RObject(); $obj->setSource($row); $obj->setCollection($this->_collection); $obj->setId($row["_id"]); return $obj; } /** * 查找一行数据,以数组的形式返回 * * @param string $id 主键_id值 * @return array */ function findOne($id = null) { if (!is_null($id)) { $this->id($id); } $this->limit(1); $all = $this->findAll(); return empty($all) ? array() : $all[0]; } /** * 查找一行数据,但只返回ID数据 * * @param string $id 主键_id值 * @return RObjct */ function findId($id = null) { if (!is_null($id)) { $this->id($id); } $this->_results = array(); $this->_results["_id"] = 1; return $this->find(); } /** * 根据请求的参数查询数据 * * @param string $requestPkName 值为主键值的请求参数 * @return RObject */ function findx($requestPkName = "id") { return $this->find(x($requestPkName)); } /** * 取出所有记录 * * @param boolean $keepId 是否保留ID的原始状态 * @return array */ function findAll($keepId = true) { $rets = array(); foreach ($this->cursor() as $value) { if ($this->_noPk) { unset($value["_id"]); } else { if (!$keepId && isset($value["_id"]) && ($value["_id"] instanceof MongoId)) { $value["_id"] = $value["_id"]->__toString(); } } $rets[] = $value; } return $rets; } /** * 分页 * * @param array $params 分页参数 * @param string $style 分页样式 * @return RPage */ function page(array $params = array(), $style = null) { import("RPage"); if (!class_exists("RPage")) { exit("You must use the method " . __METHOD__ . "() with page plugin."); } $page = RPage::pageWithStyle($style, $params); $this->offset($page->offset()); $this->limit($page->size()); $page->setRows($this->findAll()); return $page; } /** * 计算符合条件的行数 * * @param boolean $withLimit limit()/offset()方法是否有效 * @return integer */ function count($withLimit = false) { return $this->cursor()->count($withLimit); } /** * Insert new record * * @param array $attrs attributes of new record * @param boolean $safe check result * @return boolean */ function insert(array $attrs, $safe = false) { $bool = $this->_collection->insert($attrs, array( "safe" => $safe )); if ($bool) { import("@.RMongo"); if ($attrs["_id"] instanceof MongoId) { RMongo::setLastInsertId($attrs["_id"]->__toString()); } else { RMongo::setLastInsertId($attrs["_id"]); } } return $bool; } /** * 插入新的行,_id是上一行的ID加1 * * @param array $attrs 新行的属性集 * @return boolean */ function insertNext(array $attrs) { $response = $this->_db->execute('function insertObject(o, myCollection) { var x = db.getCollection(myCollection); while( 1 ) { // determine next _id value to try var c = x.find({},{_id:1}).sort({_id:-1}).limit(1); var i = c.hasNext() ? c.next()._id + 1 : 1; o._id = i; x.insert(o); var err = db.getLastErrorObj(); if( err && err.code ) { if( err.code == 11000 /* dup key */ ) continue; else print("unexpected error inserting data: " + tojson(err)); } break; } return o._id; }', array( $attrs, $this->_collectionName )); if ($response["ok"]) { import("@.RMongo"); RMongo::setLastInsertId($response["retval"]); } return $response["ok"]; } /** * 删除符合条件的记录 * * @return boolean */ function delete() { return $this->_collection->remove($this->criteria()); } /** * 更改或插入新的对象 * * 在当前驱动下不能正常工作 * * @param array $obj 新的对象 * @return boolean */ function upsert(array $obj) { return $this->_collection->update($this->criteria(), $obj, array( "upsert" => true, "multiple" => true)); } /** * 批量插入一组新的数据 * * @param array $array 每一个元素包含一个要插入的行 * @return boolean */ function batchInsert(array $array) { return $this->_collection->batchInsert($array); } /** * 当前操作的集合 * * @return MongoCollection */ function collection() { return $this->_collection; } /** * 当前操作的数据库 * * @return MongoDB */ function db() { return $this->_db; } } ?>