首页 > 代码库 > Yii2 mongodb 扩展的where的条件增加大于 小于号
Yii2 mongodb 扩展的where的条件增加大于 小于号
1. mongodb的where中有比較丰富的 条件。例如以下:
static $builders = [ 'NOT' => 'buildNotCondition', 'AND' => 'buildAndCondition', 'OR' => 'buildOrCondition', 'BETWEEN' => 'buildBetweenCondition', 'NOT BETWEEN' => 'buildBetweenCondition', 'IN' => 'buildInCondition', 'NOT IN' => 'buildInCondition', 'REGEX' => 'buildRegexCondition', 'LIKE' => 'buildLikeCondition', ];
可是没有大于和小于等,因此我们须要增加大于。大于等于, 小于。小于等于
增加函数部分为:
在vendor/yiisoft/yii2-mongodb/collection.php
增加函数:
public function buildGtCondition($operator, $operands) { if (!isset($operands[0], $operands[1])) { throw new InvalidParamException("Operator '$operator' requires two operands."); } list($column, $value) = $operands; return [$column => ['?gt' => $value]]; } public function buildGteCondition($operator, $operands) { if (!isset($operands[0], $operands[1])) { throw new InvalidParamException("Operator '$operator' requires two operands."); } list($column, $value) = $operands; return [$column => ['?gte' => $value]]; } public function buildLtCondition($operator, $operands) { if (!isset($operands[0], $operands[1])) { throw new InvalidParamException("Operator '$operator' requires two operands."); } list($column, $value) = $operands; return [$column => ['?lt' => $value]]; } public function buildLteCondition($operator, $operands) { if (!isset($operands[0], $operands[1])) { throw new InvalidParamException("Operator '$operator' requires two operands."); } list($column, $value) = $operands; return [$column => ['?buildCondition函数里面增加以下的部分代码lte' => $value]]; }
public function buildCondition($condition) { static $builders = [ 'NOT' => 'buildNotCondition', 'AND' => 'buildAndCondition', 'OR' => 'buildOrCondition', 'BETWEEN' => 'buildBetweenCondition', 'NOT BETWEEN' => 'buildBetweenCondition', 'IN' => 'buildInCondition', 'NOT IN' => 'buildInCondition', 'REGEX' => 'buildRegexCondition', 'LIKE' => 'buildLikeCondition', '>' => 'buildGtCondition', '>=' => 'buildGteCondition', '<' => 'buildLtCondition', '<=' => 'buildLteCondition', ];
最后collection.php的代码例如以下:
<?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace yii\mongodb; use yii\base\InvalidParamException; use yii\base\Object; use Yii; /** * Collection represents the Mongo collection information. * * A collection object is usually created by calling [[Database::getCollection()]] or [[Connection::getCollection()]]. * * Collection provides the basic interface for the Mongo queries, mostly: insert, update, delete operations. * For example: * * ~~~ * $collection = Yii::$app->mongodb->getCollection('customer'); * $collection->insert(['name' => 'John Smith', 'status' => 1]); * ~~~ * * To perform "find" queries, please use [[Query]] instead. * * Mongo uses JSON format to specify query conditions with quite specific syntax. * However Collection class provides the ability of "translating" common condition format used "yii\db\*" * into Mongo condition. * For example: * ~~~ * $condition = [ * [ * 'OR', * ['AND', ['first_name' => 'John'], ['last_name' => 'Smith']], * ['status' => [1, 2, 3]] * ], * ]; * print_r($collection->buildCondition($condition)); * // outputs : * [ * '$or' => [ * [ * 'first_name' => 'John', * 'last_name' => 'John', * ], * [ * 'status' => ['$in' => [1, 2, 3]], * ] * ] * ] * ~~~ * * Note: condition values for the key '_id' will be automatically cast to [[\MongoId]] instance, * even if they are plain strings. However, if you have other columns, containing [[\MongoId]], you * should take care of possible typecast on your own. * * @property string $fullName Full name of this collection, including database name. This property is * read-only. * @property array $lastError Last error information. This property is read-only. * @property string $name Name of this collection. This property is read-only. * * @author Paul Klimov <klimov.paul@gmail.com> * @since 2.0 */ class Collection extends Object { /** * @var \MongoCollection Mongo collection instance. */ public $mongoCollection; /** * @return string name of this collection. */ public function getName() { return $this->mongoCollection->getName(); } /** * @return string full name of this collection, including database name. */ public function getFullName() { return $this->mongoCollection->__toString(); } /** * @return array last error information. */ public function getLastError() { return $this->mongoCollection->db->lastError(); } /** * Composes log/profile token. * @param string $command command name * @param array $arguments command arguments. * @return string token. */ protected function composeLogToken($command, $arguments = []) { $parts = []; foreach ($arguments as $argument) { $parts[] = is_scalar($argument) ?
$argument : $this->encodeLogData($argument); } return $this->getFullName() . '.' . $command . '(' . implode(', ', $parts) . ')'; } /** * Encodes complex log data into JSON format string. * @param mixed $data raw data. * @return string encoded data string. */ protected function encodeLogData($data) { return json_encode($this->processLogData($data)); } /** * Pre-processes the log data before sending it to `json_encode()`. * @param mixed $data raw data. * @return mixed the processed data. */ protected function processLogData($data) { if (is_object($data)) { if ($data instanceof \MongoId || $data instanceof \MongoRegex || $data instanceof \MongoDate || $data instanceof \MongoInt32 || $data instanceof \MongoInt64 || $data instanceof \MongoTimestamp ) { $data = http://www.mamicode.com/get_class($data) . '(' . $data->__toString() . ')';>
$data['_id'] : $data->_id; } catch (\Exception $e) { Yii::endProfile($token, __METHOD__); throw new Exception($e->getMessage(), (int) $e->getCode(), $e); } } /** * Removes data from the collection. * @param array $condition description of records to remove. * @param array $options list of options in format: optionName => optionValue. * @return integer|boolean number of updated documents or whether operation was successful. * @throws Exception on failure. * @see http://www.php.net/manual/en/mongocollection.remove.php */ public function remove($condition = [], $options = []) { $condition = $this->buildCondition($condition); $options = array_merge(['w' => 1, 'justOne' => false], $options); $token = $this->composeLogToken('remove', [$condition, $options]); Yii::info($token, __METHOD__); try { Yii::beginProfile($token, __METHOD__); $result = $this->mongoCollection->remove($condition, $options); $this->tryResultError($result); Yii::endProfile($token, __METHOD__); if (is_array($result) && array_key_exists('n', $result)) { return $result['n']; } else { return true; } } catch (\Exception $e) { Yii::endProfile($token, __METHOD__); throw new Exception($e->getMessage(), (int) $e->getCode(), $e); } } /** * Returns a list of distinct values for the given column across a collection. * @param string $column column to use. * @param array $condition query parameters. * @return array|boolean array of distinct values, or "false" on failure. * @throws Exception on failure. */ public function distinct($column, $condition = []) { $condition = $this->buildCondition($condition); $token = $this->composeLogToken('distinct', [$column, $condition]); Yii::info($token, __METHOD__); try { Yii::beginProfile($token, __METHOD__); $result = $this->mongoCollection->distinct($column, $condition); Yii::endProfile($token, __METHOD__); return $result; } catch (\Exception $e) { Yii::endProfile($token, __METHOD__); throw new Exception($e->getMessage(), (int) $e->getCode(), $e); } } /** * Performs aggregation using Mongo Aggregation Framework. * @param array $pipeline list of pipeline operators, or just the first operator * @param array $pipelineOperator additional pipeline operator. You can specify additional * pipelines via third argument, fourth argument etc. * @return array the result of the aggregation. * @throws Exception on failure. * @see http://docs.mongodb.org/manual/applications/aggregation/ */ public function aggregate($pipeline, $pipelineOperator = []) { $args = func_get_args(); $token = $this->composeLogToken('aggregate', $args); Yii::info($token, __METHOD__); try { Yii::beginProfile($token, __METHOD__); $result = call_user_func_array([$this->mongoCollection, 'aggregate'], $args); $this->tryResultError($result); Yii::endProfile($token, __METHOD__); return $result['result']; } catch (\Exception $e) { Yii::endProfile($token, __METHOD__); throw new Exception($e->getMessage(), (int) $e->getCode(), $e); } } /** * Performs aggregation using Mongo "group" command. * @param mixed $keys fields to group by. If an array or non-code object is passed, * it will be the key used to group results. If instance of [[\MongoCode]] passed, * it will be treated as a function that returns the key to group by. * @param array $initial Initial value of the aggregation counter object. * @param \MongoCode|string $reduce function that takes two arguments (the current * document and the aggregation to this point) and does the aggregation. * Argument will be automatically cast to [[\MongoCode]]. * @param array $options optional parameters to the group command. Valid options include: * - condition - criteria for including a document in the aggregation. * - finalize - function called once per unique key that takes the final output of the reduce function. * @return array the result of the aggregation. * @throws Exception on failure. * @see http://docs.mongodb.org/manual/reference/command/group/ */ public function group($keys, $initial, $reduce, $options = []) { if (!($reduce instanceof \MongoCode)) { $reduce = new \MongoCode((string) $reduce); } if (array_key_exists('condition', $options)) { $options['condition'] = $this->buildCondition($options['condition']); } if (array_key_exists('finalize', $options)) { if (!($options['finalize'] instanceof \MongoCode)) { $options['finalize'] = new \MongoCode((string) $options['finalize']); } } $token = $this->composeLogToken('group', [$keys, $initial, $reduce, $options]); Yii::info($token, __METHOD__); try { Yii::beginProfile($token, __METHOD__); // Avoid possible E_DEPRECATED for $options: if (empty($options)) { $result = $this->mongoCollection->group($keys, $initial, $reduce); } else { $result = $this->mongoCollection->group($keys, $initial, $reduce, $options); } $this->tryResultError($result); Yii::endProfile($token, __METHOD__); if (array_key_exists('retval', $result)) { return $result['retval']; } else { return []; } } catch (\Exception $e) { Yii::endProfile($token, __METHOD__); throw new Exception($e->getMessage(), (int) $e->getCode(), $e); } } /** * Performs aggregation using Mongo "map reduce" mechanism. * Note: this function will not return the aggregation result, instead it will * write it inside the another Mongo collection specified by "out" parameter. * For example: * * ~~~ * $customerCollection = Yii::$app->mongo->getCollection('customer'); * $resultCollectionName = $customerCollection->mapReduce( * 'function () {emit(this.status, this.amount)}', * 'function (key, values) {return Array.sum(values)}', * 'mapReduceOut', * ['status' => 3] * ); * $query = new Query(); * $results = $query->from($resultCollectionName)->all(); * ~~~ * * @param \MongoCode|string $map function, which emits map data from collection. * Argument will be automatically cast to [[\MongoCode]]. * @param \MongoCode|string $reduce function that takes two arguments (the map key * and the map values) and does the aggregation. * Argument will be automatically cast to [[\MongoCode]]. * @param string|array $out output collection name. It could be a string for simple output * ('outputCollection'), or an array for parametrized output (['merge' => 'outputCollection']). * You can pass ['inline' => true] to fetch the result at once without temporary collection usage. * @param array $condition criteria for including a document in the aggregation. * @param array $options additional optional parameters to the mapReduce command. Valid options include: * - sort - array - key to sort the input documents. The sort key must be in an existing index for this collection. * - limit - the maximum number of documents to return in the collection. * - finalize - function, which follows the reduce method and modifies the output. * - scope - array - specifies global variables that are accessible in the map, reduce and finalize functions. * - jsMode - boolean -Specifies whether to convert intermediate data into BSON format between the execution of the map and reduce functions. * - verbose - boolean - specifies whether to include the timing information in the result information. * @return string|array the map reduce output collection name or output results. * @throws Exception on failure. */ public function mapReduce($map, $reduce, $out, $condition = [], $options = []) { if (!($map instanceof \MongoCode)) { $map = new \MongoCode((string) $map); } if (!($reduce instanceof \MongoCode)) { $reduce = new \MongoCode((string) $reduce); } $command = [ 'mapReduce' => $this->getName(), 'map' => $map, 'reduce' => $reduce, 'out' => $out ]; if (!empty($condition)) { $command['query'] = $this->buildCondition($condition); } if (array_key_exists('finalize', $options)) { if (!($options['finalize'] instanceof \MongoCode)) { $options['finalize'] = new \MongoCode((string) $options['finalize']); } } if (!empty($options)) { $command = array_merge($command, $options); } $token = $this->composeLogToken('mapReduce', [$map, $reduce, $out]); Yii::info($token, __METHOD__); try { Yii::beginProfile($token, __METHOD__); $command = array_merge(['mapReduce' => $this->getName()], $command); $result = $this->mongoCollection->db->command($command); $this->tryResultError($result); Yii::endProfile($token, __METHOD__); return array_key_exists('results', $result) ?
$result['results'] : $result['result']; } catch (\Exception $e) { Yii::endProfile($token, __METHOD__); throw new Exception($e->getMessage(), (int) $e->getCode(), $e); } } /** * Performs full text search. * @param string $search string of terms that MongoDB parses and uses to query the text index. * @param array $condition criteria for filtering a results list. * @param array $fields list of fields to be returned in result. * @param array $options additional optional parameters to the mapReduce command. Valid options include: * - limit - the maximum number of documents to include in the response (by default 100). * - language - the language that determines the list of stop words for the search * and the rules for the stemmer and tokenizer. If not specified, the search uses the default * language of the index. * @return array the highest scoring documents, in descending order by score. * @throws Exception on failure. */ public function fullTextSearch($search, $condition = [], $fields = [], $options = []) { $command = [ 'search' => $search ]; if (!empty($condition)) { $command['filter'] = $this->buildCondition($condition); } if (!empty($fields)) { $command['project'] = $fields; } if (!empty($options)) { $command = array_merge($command, $options); } $token = $this->composeLogToken('text', $command); Yii::info($token, __METHOD__); try { Yii::beginProfile($token, __METHOD__); $command = array_merge(['text' => $this->getName()], $command); $result = $this->mongoCollection->db->command($command); $this->tryResultError($result); Yii::endProfile($token, __METHOD__); return $result['results']; } catch (\Exception $e) { Yii::endProfile($token, __METHOD__); throw new Exception($e->getMessage(), (int) $e->getCode(), $e); } } /** * Checks if command execution result ended with an error. * @param mixed $result raw command execution result. * @throws Exception if an error occurred. */ protected function tryResultError($result) { if (is_array($result)) { if (!empty($result['errmsg'])) { $errorMessage = $result['errmsg']; } elseif (!empty($result['err'])) { $errorMessage = $result['err']; } if (isset($errorMessage)) { if (array_key_exists('code', $result)) { $errorCode = (int) $result['code']; } elseif (array_key_exists('ok', $result)) { $errorCode = (int) $result['ok']; } else { $errorCode = 0; } throw new Exception($errorMessage, $errorCode); } } elseif (!$result) { throw new Exception('Unknown error, use "w=1" option to enable error tracking'); } } /** * Throws an exception if there was an error on the last operation. * @throws Exception if an error occurred. */ protected function tryLastError() { $this->tryResultError($this->getLastError()); } /** * Converts "\yii\db\*" quick condition keyword into actual Mongo condition keyword. * @param string $key raw condition key. * @return string actual key. */ protected function normalizeConditionKeyword($key) { static $map = [ 'AND' => '$and', 'OR' => '$or', 'IN' => '$in', 'NOT IN' => '$nin', ]; $matchKey = strtoupper($key); if (array_key_exists($matchKey, $map)) { return $map[$matchKey]; } else { return $key; } } /** * Converts given value into [[MongoId]] instance. * If array given, each element of it will be processed. * @param mixed $rawId raw id(s). * @return array|\MongoId normalized id(s). */ protected function ensureMongoId($rawId) { if (is_array($rawId)) { $result = []; foreach ($rawId as $key => $value) { $result[$key] = $this->ensureMongoId($value); } return $result; } elseif (is_object($rawId)) { if ($rawId instanceof \MongoId) { return $rawId; } else { $rawId = (string) $rawId; } } try { $mongoId = new \MongoId($rawId); } catch (\MongoException $e) { // invalid id format $mongoId = $rawId; } return $mongoId; } public function buildGtCondition($operator, $operands) { if (!isset($operands[0], $operands[1])) { throw new InvalidParamException("Operator '$operator' requires two operands."); } list($column, $value) = $operands; return [$column => ['?gt' => $value]]; } public function buildGteCondition($operator, $operands) { if (!isset($operands[0], $operands[1])) { throw new InvalidParamException("Operator '$operator' requires two operands."); } list($column, $value) = $operands; return [$column => ['?gte' => $value]]; } public function buildLtCondition($operator, $operands) { if (!isset($operands[0], $operands[1])) { throw new InvalidParamException("Operator '$operator' requires two operands."); } list($column, $value) = $operands; return [$column => ['?lt' => $value]]; } public function buildLteCondition($operator, $operands) { if (!isset($operands[0], $operands[1])) { throw new InvalidParamException("Operator '$operator' requires two operands."); } list($column, $value) = $operands; return [$column => ['?
lte' => $value]]; } /** * Parses the condition specification and generates the corresponding Mongo condition. * @param array $condition the condition specification. Please refer to [[Query::where()]] * on how to specify a condition. * @return array the generated Mongo condition * @throws InvalidParamException if the condition is in bad format */ public function buildCondition($condition) { static $builders = [ 'NOT' => 'buildNotCondition', 'AND' => 'buildAndCondition', 'OR' => 'buildOrCondition', 'BETWEEN' => 'buildBetweenCondition', 'NOT BETWEEN' => 'buildBetweenCondition', 'IN' => 'buildInCondition', 'NOT IN' => 'buildInCondition', 'REGEX' => 'buildRegexCondition', 'LIKE' => 'buildLikeCondition', '>' => 'buildGtCondition', '>=' => 'buildGteCondition', '<' => 'buildLtCondition', '<=' => 'buildLteCondition', ]; if (!is_array($condition)) { throw new InvalidParamException('Condition should be an array.'); } elseif (empty($condition)) { return []; } if (isset($condition[0])) { // operator format: operator, operand 1, operand 2, ... $operator = strtoupper($condition[0]); if (isset($builders[$operator])) { $method = $builders[$operator]; array_shift($condition); return $this->$method($operator, $condition); } else { throw new InvalidParamException('Found unknown operator in query: ' . $operator); } } else { // hash format: 'column1' => 'value1', 'column2' => 'value2', ... return $this->buildHashCondition($condition); } } /** * Creates a condition based on column-value pairs. * @param array $condition the condition specification. * @return array the generated Mongo condition. */ public function buildHashCondition($condition) { $result = []; foreach ($condition as $name => $value) { if (strncmp('$', $name, 1) === 0) { // Native Mongo condition: $result[$name] = $value; } else { if (is_array($value)) { if (array_key_exists(0, $value)) { // Quick IN condition: $result = array_merge($result, $this->buildInCondition('IN', [$name, $value])); } else { // Mongo complex condition: $result[$name] = $value; } } else { // Direct match: if ($name == '_id') { $value = http://www.mamicode.com/$this->ensureMongoId($value);>
Yii2 mongodb 扩展的where的条件增加大于 小于号