1. 程式人生 > >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 => ['?lte' => $value]];
    }
buildCondition函式裡面加入下面的部分程式碼
 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 <[email protected]>
 * @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 = get_class($data) . '(' . $data->__toString() . ')';
            } elseif ($data instanceof \MongoCode) {
                $data = 'MongoCode( ' . $data->__toString() . ' )';
            } elseif ($data instanceof \MongoBinData) {
                $data = 'MongoBinData(...)';
            } elseif ($data instanceof \MongoDBRef) {
                $data = 'MongoDBRef(...)';
            } elseif ($data instanceof \MongoMinKey || $data instanceof \MongoMaxKey) {
                $data = get_class($data);
            } else {
                $result = [];
                foreach ($data as $name => $value) {
                    $result[$name] = $value;
                }
                $data = $result;
            }

            if ($data === []) {
                return new \stdClass();
            }
        }

        if (is_array($data)) {
            foreach ($data as $key => $value) {
                if (is_array($value) || is_object($value)) {
                    $data[$key] = $this->processLogData($value);
                }
            }
        }

        return $data;
    }

    /**
     * Drops this collection.
     * @throws Exception on failure.
     * @return boolean whether the operation successful.
     */
    public function drop()
    {
        $token = $this->composeLogToken('drop');
        Yii::info($token, __METHOD__);
        try {
            Yii::beginProfile($token, __METHOD__);
            $result = $this->mongoCollection->drop();
            $this->tryResultError($result);
            Yii::endProfile($token, __METHOD__);

            return true;
        } catch (\Exception $e) {
            Yii::endProfile($token, __METHOD__);
            throw new Exception($e->getMessage(), (int) $e->getCode(), $e);
        }
    }

    /**
     * Creates an index on the collection and the specified fields.
     * @param array|string $columns column name or list of column names.
     * If array is given, each element in the array has as key the field name, and as
     * value either 1 for ascending sort, or -1 for descending sort.
     * You can specify field using native numeric key with the field name as a value,
     * in this case ascending sort will be used.
     * For example:
     * ~~~
     * [
     *     'name',
     *     'status' => -1,
     * ]
     * ~~~
     * @param array $options list of options in format: optionName => optionValue.
     * @throws Exception on failure.
     * @return boolean whether the operation successful.
     */
    public function createIndex($columns, $options = [])
    {
        $columns = (array)$columns;
        $keys = $this->normalizeIndexKeys($columns);
        $token = $this->composeLogToken('createIndex', [$keys, $options]);
        $options = array_merge(['w' => 1], $options);
        Yii::info($token, __METHOD__);
        try {
            Yii::beginProfile($token, __METHOD__);
            if (method_exists($this->mongoCollection, 'createIndex')) {
                $result = $this->mongoCollection->createIndex($keys, $options);
            } else {
                $result = $this->mongoCollection->ensureIndex($keys, $options);
            }
            $this->tryResultError($result);
            Yii::endProfile($token, __METHOD__);

            return true;
        } catch (\Exception $e) {
            Yii::endProfile($token, __METHOD__);
            throw new Exception($e->getMessage(), (int) $e->getCode(), $e);
        }
    }

    /**
     * Drop indexes for specified column(s).
     * @param string|array $columns column name or list of column names.
     * If array is given, each element in the array has as key the field name, and as
     * value either 1 for ascending sort, or -1 for descending sort.
     * Use value 'text' to specify text index.
     * You can specify field using native numeric key with the field name as a value,
     * in this case ascending sort will be used.
     * For example:
     * ~~~
     * [
     *     'name',
     *     'status' => -1,
     *     'description' => 'text',
     * ]
     * ~~~
     * @throws Exception on failure.
     * @return boolean whether the operation successful.
     */
    public function dropIndex($columns)
    {
        $columns = (array)$columns;
        $keys = $this->normalizeIndexKeys($columns);
        $token = $this->composeLogToken('dropIndex', [$keys]);
        Yii::info($token, __METHOD__);
        try {
            $result = $this->mongoCollection->deleteIndex($keys);
            $this->tryResultError($result);

            return true;
        } catch (\Exception $e) {
            Yii::endProfile($token, __METHOD__);
            throw new Exception($e->getMessage(), (int) $e->getCode(), $e);
        }
    }

    /**
     * Compose index keys from given columns/keys list.
     * @param array $columns raw columns/keys list.
     * @return array normalizes index keys array.
     */
    protected function normalizeIndexKeys($columns)
    {
        $keys = [];
        foreach ($columns as $key => $value) {
            if (is_numeric($key)) {
                $keys[$value] = \MongoCollection::ASCENDING;
            } else {
                $keys[$key] = $value;
            }
        }

        return $keys;
    }

    /**
     * Drops all indexes for this collection.
     * @throws Exception on failure.
     * @return integer count of dropped indexes.
     */
    public function dropAllIndexes()
    {
        $token = $this->composeLogToken('dropIndexes');
        Yii::info($token, __METHOD__);
        try {
            $result = $this->mongoCollection->deleteIndexes();
            $this->tryResultError($result);

            return $result['nIndexesWas'];
        } catch (\Exception $e) {
            Yii::endProfile($token, __METHOD__);
            throw new Exception($e->getMessage(), (int) $e->getCode(), $e);
        }
    }

    /**
     * Returns a cursor for the search results.
     * In order to perform "find" queries use [[Query]] class.
     * @param array $condition query condition
     * @param array $fields fields to be selected
     * @return \MongoCursor cursor for the search results
     * @see Query
     */
    public function find($condition = [], $fields = [])
    {
        return $this->mongoCollection->find($this->buildCondition($condition), $fields);
    }

    /**
     * Returns a single document.
     * @param array $condition query condition
     * @param array $fields fields to be selected
     * @return array|null the single document. Null is returned if the query results in nothing.
     * @see http://www.php.net/manual/en/mongocollection.findone.php
     */
    public function findOne($condition = [], $fields = [])
    {
        return $this->mongoCollection->findOne($this->buildCondition($condition), $fields);
    }

    /**
     * Updates a document and returns it.
     * @param array $condition query condition
     * @param array $update update criteria
     * @param array $fields fields to be returned
     * @param array $options list of options in format: optionName => optionValue.
     * @return array|null the original document, or the modified document when $options['new'] is set.
     * @throws Exception on failure.
     * @see http://www.php.net/manual/en/mongocollection.findandmodify.php
     */
    public function findAndModify($condition, $update, $fields = [], $options = [])
    {
        $condition = $this->buildCondition($condition);
        $token = $this->composeLogToken('findAndModify', [$condition, $update, $fields, $options]);
        Yii::info($token, __METHOD__);
        try {
            Yii::beginProfile($token, __METHOD__);
            $result = $this->mongoCollection->findAndModify($condition, $update, $fields, $options);
            Yii::endProfile($token, __METHOD__);

            return $result;
        } catch (\Exception $e) {
            Yii::endProfile($token, __METHOD__);
            throw new Exception($e->getMessage(), (int) $e->getCode(), $e);
        }
    }

    /**
     * Inserts new data into collection.
     * @param array|object $data data to be inserted.
     * @param array $options list of options in format: optionName => optionValue.
     * @return \MongoId new record id instance.
     * @throws Exception on failure.
     */
    public function insert($data, $options = [])
    {
        $token = $this->composeLogToken('insert', [$data]);
        Yii::info($token, __METHOD__);
        try {
            Yii::beginProfile($token, __METHOD__);
            $options = array_merge(['w' => 1], $options);
            $this->tryResultError($this->mongoCollection->insert($data, $options));
            Yii::endProfile($token, __METHOD__);

            return is_array($data) ? $data['_id'] : $data->_id;
        } catch (\Exception $e) {
            Yii::endProfile($token, __METHOD__);
            throw new Exception($e->getMessage(), (int) $e->getCode(), $e);
        }
    }

    /**
     * Inserts several new rows into collection.
     * @param array $rows array of arrays or objects to be inserted.
     * @param array $options list of options in format: optionName => optionValue.
     * @return array inserted data, each row will have "_id" key assigned to it.
     * @throws Exception on failure.
     */
    public function batchInsert($rows, $options = [])
    {
        $token = $this->composeLogToken('batchInsert', [$rows]);
        Yii::info($token, __METHOD__);
        try {
            Yii::beginProfile($token, __METHOD__);
            $options = array_merge(['w' => 1], $options);
            $this->tryResultError($this->mongoCollection->batchInsert($rows, $options));
            Yii::endProfile($token, __METHOD__);

            return $rows;
        } catch (\Exception $e) {
            Yii::endProfile($token, __METHOD__);
            throw new Exception($e->getMessage(), (int) $e->getCode(), $e);
        }
    }

    /**
     * Updates the rows, which matches given criteria by given data.
     * Note: for "multiple" mode Mongo requires explicit strategy "$set" or "$inc"
     * to be specified for the "newData". If no strategy is passed "$set" will be used.
     * @param array $condition description of the objects to update.
     * @param array $newData the object with which to update the matching records.
     * @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.
     */
    public function update($condition, $newData, $options = [])
    {
        $condition = $this->buildCondition($condition);
        $options = array_merge(['w' => 1, 'multiple' => true], $options);
        if ($options['multiple']) {
            $keys = array_keys($newData);
            if (!empty($keys) && strncmp('$', $keys[0], 1) !== 0) {
                $newData = ['$set' => $newData];
            }
        }
        $token = $this->composeLogToken('update', [$condition, $newData, $options]);
        Yii::info($token, __METHOD__);
        try {
            Yii::beginProfile($token, __METHOD__);
            $result = $this->mongoCollection->update($condition, $newData, $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);
        }
    }

    /**
     * Update the existing database data, otherwise insert this data
     * @param array|object $data data to be updated/inserted.
     * @param array $options list of options in format: optionName => optionValue.
     * @return \MongoId updated/new record id instance.
     * @throws Exception on failure.
     */
    public function save($data, $options = [])
    {
        $token = $this->composeLogToken('save', [$data]);
        Yii::info($token, __METHOD__);
        try {
            Yii::beginProfile($token, __METHOD__);
            $options = array_merge(['w' => 1], $options);
            $this->tryResultError($this->mongoCollection->save($data, $options));
            Yii::endProfile($token, __METHOD__);

            return is_array($data) ? $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 = $this->ensureMongoId($value);
                    }
                    $result[$name] = $value;
                }
            }
        }

        return $result;
    }

    /**
     * Composes `NOT` condition.
     * @param string $operator the operator to use for connecting the given operands
     * @param array $operands the Mongo conditions to connect.
     * @return array the generated Mongo condition.
     * @throws InvalidParamException if wrong number of operands have been given.
     */
    public function buildNotCondition($operator, $operands)
    {
        if (!isset($operands[0], $operands[1])) {
            throw new InvalidParamException("Operator '$operator' requires two operands.");
        }

        list($name, $value) = $operands;

        $result = [];
        if (is_array($value)) {
            $result[$name] = ['$not' => $this->buildCondition($value)];
        } else {
            if ($name == '_id') {
                $value = $this->ensureMongoId($value);
            }
            $result[$name] = ['$ne' => $value];
        }

        return $result;
    }

    /**
     * Connects two or more conditions with the `AND` operator.
     * @param string $operator the operator to use for connecting the given operands
     * @param array $operands the Mongo conditions to connect.
     * @return array the generated Mongo condition.
     */
    public function buildAndCondition($operator, $operands)
    {
        $operator = $this->normalizeConditionKeyword($operator);
        $parts = [];
        foreach ($operands as $operand) {
            $parts[] = $this->buildCondition($operand);
        }

        return [$operator => $parts];
    }

    /**
     * Connects two or more conditions with the `OR` operator.
     * @param string $operator the operator to use for connecting the given operands
     * @param array $operands the Mongo conditions to connect.
     * @return array the generated Mongo condition.
     */
    public function buildOrCondition($operator, $operands)
    {
        $operator = $this->normalizeConditionKeyword($operator);
        $parts = [];
        foreach ($operands as $operand) {
            $parts[] = $this->buildCondition($operand);
        }

        return [$operator => $parts];
    }

    /**
     * Creates an Mongo condition, which emulates the `BETWEEN` operator.
     * @param string $operator the operator to use
     * @param array $operands the first operand is the column name. The second and third operands
     * describe the interval that column value should be in.
     * @return array the generated Mongo condition.
     * @throws InvalidParamException if wrong number of operands have been given.
     */
    public function buildBetweenCondition($operator, $operands)
    {
        if (!isset($operands[0], $operands[1], $operands[2])) {
            throw new InvalidParamException("Operator '$operator' requires three operands.");
        }
        list($column, $value1, $value2) = $operands;
        if (strncmp('NOT', $operator, 3) === 0) {
            return [
                $column => [
                    '$lt' => $value1,
                    '$gt' => $value2,
                ]
            ];
        } else {
            return [
                $column => [
                    '$gte' => $value1,
                    '$lte' => $value2,
                ]
            ];
        }
    }

    /**
     * Creates an Mongo condition with the `IN` operator.
     * @param string $operator the operator to use (e.g. `IN` or `NOT IN`)
     * @param array $operands the first operand is the column name. If it is an array
     * a composite IN condition will be generated.
     * The second operand is an array of values that column value should be among.
     * @return array the generated Mongo condition.
     * @throws InvalidParamException if wrong number of operands have been given.
     */
    public function buildInCondition($operator, $operands)
    {
        if (!isset($operands[0], $operands[1])) {
            throw new InvalidParamException("Operator '$operator' requires two operands.");
        }

        list($column, $values) = $operands;

        $values = (array) $values;

        if (!is_array($column)) {
            $columns = [$column];
            $values = [$column => $values];
        } elseif (count($column) < 2) {
            $columns = $column;
            $values = [$column[0] => $values];
        } else {
            $columns = $column;
        }

        $operator = $this->normalizeConditionKeyword($operator);
        $result = [];
        foreach ($columns as $column) {
            if ($column == '_id') {
                $inValues = $this->ensureMongoId($values[$column]);
            } else {
                $inValues = $values[$column];
            }
            $result[$column][$operator] = array_values($inValues);
        }

        return $result;
    }

    /**
     * Creates a Mongo regular expression condition.
     * @param string $operator the operator to use
     * @param array $operands the first operand is the column name.
     * The second operand is a single value that column value should be compared with.
     * @return array the generated Mongo condition.
     * @throws InvalidParamException if wrong number of operands have been given.
     */
    public function buildRegexCondition($operator, $operands)
    {
        if (!isset($operands[0], $operands[1])) {
            throw new InvalidParamException("Operator '$operator' requires two operands.");
        }
        list($column, $value) = $operands;
        if (!($value instanceof \MongoRegex)) {
            $value = new \MongoRegex($value);
        }

        return [$column => $value];
    }

    /**
     * Creates a Mongo condition, which emulates the `LIKE` operator.
     * @param string $operator the operator to use
     * @param array $operands the first operand is the column name.
     * The second operand is a single value that column value should be compared with.
     * @return array the generated Mongo condition.
     * @throws InvalidParamException if wrong number of operands have been given.
     */
    public function buildLikeCondition($operator, $operands)
    {
        if (!isset($operands[0], $operands[1])) {
            throw new InvalidParamException("Operator '$operator' requires two operands.");
        }
        list($column, $value) = $operands;
        if (!($value instanceof \MongoRegex)) {
            $value = new \MongoRegex('/' . preg_quote($value) . '/i');
        }

        return [$column => $value];
    }
}


相關推薦

Yii2 mongodb 擴充套件where條件加入大於 小於

1. mongodb的where中有比較豐富的 條件,如下: static $builders = [ 'NOT' => 'buildNotCondition', 'AND' => 'buildAndCondi

Yii2查詢之where條件拼裝

熟悉Yii2的查詢條件後,用Active Record查詢資料非常方便。 以下我們介紹where()方法當中,條件的拼裝方式。 #某個值為null,會用IS NULL來生成語句: ['type' => 1, 'status' => 2]

MyBits 中大於小於如何處理

第一種方法: 用了轉義字元把>和<替換掉,然後就沒有問題了。 SELECT * FROM test WHERE 1 = 1 AND start_date  &lt;= CURRENT_DATE AND end_date &gt;= CURRENT_DAT

mybatis的大於小於轉義符號

  言簡意賅!如下   XML轉義字元 &lt;      <    小於號    &gt; &nbs

mybatis中sql語句中使用大於小於方法

目的: mapper檔案中如何使用大於小於號 例項:查詢語句 <select id="queryInfo" parameterType="com.Time" resultType

MyBatis SQL在xml中,處理大於小於的方法

第一種方法: 用了轉義字元把>和<替換掉,然後就沒有問題了。 SELECT * FROM test WHERE 1 = 1 AND start_date  &lt;= CURRENT_DATE AND end_date &gt;= CU

LaTeX大於小於

sim 寫法 ria -s 16px 否則 text 識別 大於等於 發現大部分人只回答大於等於號、小於等於號的寫法,而沒有說大於、小於號的分別寫法。 大於號:\textgreater 小於號: \textless 下面的後面要加空格,否則會識別錯誤 大於等於:\g

sqlserver儲存過程where條件引數為空不加入篩選

CREATE PROCEDURE "dbo"."TEST_PRC"( @no_in VARCHAR(20)

insert中加入where條件判斷,解決插入重複資料的問題

對於會員註冊,我們經常會做唯一性驗證,通常情況下我們有這兩種方式: 1. 資料庫表設計的時候loginName增加唯一約束 2. 註冊之前先查一下然後再去進行插入操作 針對以上兩種情況,第一種情況,增加約束的話,是最有效的,但如果表結構已經確定了,再修改起

漲知識,漲知識 :ThinkPHP框架下Where條件查詢Mysql數據庫某字段是否為空

field 打印 想要 sts bsp ech 是否為空 time inf 代碼虐我千百遍,我對代碼如初戀~ 問題: 查詢某字段app_date數據是否為NULL,正常我們實現的辦法是: $map[‘app_data‘] = array(‘eq‘,‘null

MYSQL數據類型和where條件判斷

where條件 var 否則 float 由於 是否為空 size 邏輯運算 查詢 MySQL中常見的數據類型 一、字符型 ① CHAR(N):固定N個字符長度的字符串,如果長度不夠自動空格補齊; N的範圍 0~255 ② VARCHAR(N): 存儲可變長度的字符串

MYSQL數據類型和where條件

pan use gin 如果 sta long 多個 mes 註意 MySQL中常見的數據類型 一、字符型 ① CHAR(N):固定N個字符長度的字符串,如果長度不夠自動空格補齊; N的範圍 0~255 ② VARCHAR(N): 存儲可變長度的字符串,最常用 ③

SQL where 條件順序對性能的影響有哪些

問題 哪些 ora tween 其它 個數 執行計劃 where 網上 經常有人問到oracle中的Where子句的條件書寫順序是否對SQL性能有影響,我的直覺是沒有影響,因為如果這個順序有影響,Oracle應該早就能夠做到自動優化,但一直沒有關於這方面的確鑿證據。在網上查

where條件順序與建索引順序

版本 sql查詢優化 臨時 dash 沒有 多表 測試 最小 問題 查詢時,如果數據量很大,where 後面的條件與建索引的順序相同,也沒有什麽多少差別,聚集索引稍微快點; 但where 後面的條件與建索引順序不同,速度會慢下來,到底慢多少,不同的機器會不一樣,沒有絕對的說

解決query查詢輸入geometry參數查詢不到而通過where條件可以查到的問題

gis 查詢參數 數據 ron http 顯示 src 出現 ren 解決query查詢輸入geometry參數查詢不到而通過where條件可以查到的問題 原因: 是因為geometry的坐標系和所要查詢的圖層不一樣導致的(問題引起是由於底圖中疊加了不同的坐標系的引起的)

在Mybatis中處理sql中的大於小於

字符替換 mybatis str tab amp 不能 [ ] pos table 因為xml格式中,不能隨便出現"<"、“>”等符號,所以在sql中這一類的符號要進行特殊處理 第一種方法:使用轉義字符替換特殊的符號   例如 SELECT * FROM j

tp 中 where條件,字段和字段的大小比較

比較 sta number time arr 大小 array art ring $map = array( ‘pid‘ => 0, ‘start_time‘ => ar

MyBatis SQL處理大於小於

color eight lock style bat mybatis order span 大於 MyBatis mapper文件是xml文件,需要特殊字符如大於號、小於號後需要轉義。 原字符 轉義後字符 < &lt;

Mysql中where條件一個單引號引發的性能損耗

電商 str target mysq color 日常 location 速度 avi 日常寫SQL中可能會有一些小細節忽略了導致整個sql的性能下降了好幾倍甚至幾十倍,幾百倍。以下這個示例就是mysql語句中的一個單引號(‘‘)引發的性能耗損,我相信很多朋友都遇到過,甚至

左外連接 where條件 on條件

idt ble color width size where條件 cell 數據庫 pos QL> CREATE TABLE t1 AS SELECT ROWNUM ID FROM dual CONNECT BY ROWNUM<=10; Table create