选择语言 :

 Driver_Database_Driver_Mongo::query

执行查询

目前支持插入、修改、保存(类似mysql的replace)查询

$use_connection_type 默认不传为自动判断,可传true/false,若传字符串(只支持a-z0-9的字符串),则可以切换到另外一个连接,比如传other,则可以连接到$this->_connection_other_id所对应的ID的连接

Database_Driver_Mongo_Result Driver_Database_Driver_Mongo::query( array $options [, string $as_object = null , boolean $use_connection_type = null ] )

参数列表

参数 类型 描述 默认值
$options array $options
$as_object string 是否返回对象 null
$use_connection_type boolean $use_master 是否使用主数据库,不设置则自动判断 null
返回值
  • Database_Driver_Mongo_Result
File: ./drivers/database/mongo/mongo.class.php
public function query($options, $as_object = null, $use_connection_type = null)
{
    if (IS_DEBUG)Core::debug()->log($options);

    if (is_string($options))
    {
        # 设置连接类型
        $this->_set_connection_type($use_connection_type);

        // 必需数组
        if (!is_array($as_object))$as_object = array();
        return $this->connection()->execute($options,$as_object);
    }

    $type = strtoupper($options['type']);

    $typeArr = array
    (
        'SELECT',
        'SHOW',     //显示表
        'EXPLAIN',  //分析
        'DESCRIBE', //显示结结构
        'INSERT',
        'BATCHINSERT',
        'REPLACE',
        'SAVE',
        'UPDATE',
        'REMOVE',
    );

    $slaverType = array
    (
        'SELECT',
        'SHOW',
        'EXPLAIN'
    );

    if (in_array($type, $slaverType))
    {
        if (true===$use_connection_type)
        {
            $use_connection_type = 'master';
        }
        else if (is_string($use_connection_type))
        {
            if (!preg_match('#^[a-z0-9_]+$#i', $use_connection_type))$use_connection_type = 'master';
        }
        else
        {
            $use_connection_type = 'slaver';
        }
    }
    else
    {
        $use_connection_type = 'master';
    }


    # 设置连接类型
    $this->_set_connection_type($use_connection_type);

    # 连接数据库
    $connection = $this->connection();

    if (!$options['table'])
    {
        throw new Exception('查询条件中缺少Collection');
    }

    $tablename = $this->config['table_prefix'] . $options['table'];

    if(IS_DEBUG)
    {
        static $is_sql_debug = null;

        if (null === $is_sql_debug) $is_sql_debug = (bool)Core::debug()->profiler('sql')->is_open();

        if ($is_sql_debug)
        {
            $host = $this->_get_hostname_by_connection_hash($this->connection_id());
            $benchmark = Core::debug()->profiler('sql')->start('Database', 'mongodb://'.($host['username']?$host['username'].'@':'') . $host['hostname'] . ($host['port'] && $host['port'] != '27017' ? ':' . $host['port'] : ''));
        }
    }

    $explain = null;

    try
    {
        switch ($type)
        {
            case 'SELECT':

                if ($options['distinct'])
                {
                    # 查询唯一值
                    $result = $connection->command(
                        array
                        (
                            'distinct' => $tablename,
                            'key'      => $options['distinct'] ,
                            'query'    => $options['where']
                       )
                    );

                    $last_query = 'db.'.$tablename.'.distinct('.$options['distinct'].', '.json_encode($options['where']).')';

                    if(IS_DEBUG && $is_sql_debug)
                    {
                        $count = count($result['values']);
                    }

                    if ($result && $result['ok']==1)
                    {
                        $rs = new Database_Driver_Mongo_Result(new ArrayIterator($result['values']), $options, $as_object ,$this->config);
                    }
                    else
                    {
                        throw new Exception($result['errmsg']);
                    }
                }
                elseif ($options['group_by'])
                {
                    $have_dot = false;

                    $select = $options['select'];
                    # group by
                    $group_opt = array();
                    if (1===count($options['group_by']))
                    {
                        $k = current($options['group_by']);
                        $group_opt['_id'] = '$'.$k;
                        if (!isset($select[$k]))$select[$k] = 1;
                    }
                    else
                    {
                        $group_opt['_id'] = array();
                        foreach ($options['group_by'] as $item)
                        {
                        	if (false!==strpos($item, '.'))
                        	{
                        		$have_dot = true;
                        		$group_opt['_id'][str_replace('.', '->', $item)] = '$'.$item;
                        	}
                        	else
                        	{
                                $group_opt['_id'][$item] = '$'.$item;
                        	}

                            if (!isset($select[$item]))$select[$item] = 1;
                        }
                    }

                    $last_query = 'db.'.$tablename.'.aggregate(';
                    $ops = array();
                    if ($options['where'])
                    {
                        $last_query .= '{$match: '.json_encode($options['where']).'}, ';
                        $ops[] = array
                        (
                            '$match' => $options['where']
                        );
                    }

                    $group_opt['_count'] = array('$sum'=>1);
                    if ($select)
                    {
                        foreach ($select as $k=>$v)
                        {
                            if (1===$v)
                            {
                                if (false!==strpos($k,'.'))
                                {
                                    $have_dot = true;
                                    $group_opt[str_replace('.','->',$k)] = array('$first'=>'$'.$k);
                                }
                                else
                                {
                                    $group_opt[$k] = array('$first'=>'$'.$k);
                                }
                            }
                            else
                            {
                                if (false!==strpos($v,'.'))
                                {
                                    $have_dot = true;
                                    $group_opt[str_replace('.','->',$v)] = array('$first'=>'$'.$k);
                                }
                                else
                                {
                                    $group_opt[$v] = array('$first'=>'$'.$k);
                                }
                            }
                        }
                    }

                    // 处理高级查询条件
                    if ($options['select_adv'])foreach ($options['select_adv'] as $item)
                    {
                        if (!is_array($item))continue;

                        if (preg_match('#^(.*) AS (.*)$#i', $item[0] , $m))
                        {
                            $column = $m[1];
                            $alias  = $m[2];
                        }
                        else
                        {
                            $column = $alias = $item[0];
                        }
                        $alias = str_replace('.','->',$alias);
                        if (false===$have_dot && false!==strpos($alias,'.'))
                        {
                            $have_dot = true;
                        }

                        switch ($item[1])
                        {
                            case 'max':
                            case 'min':
                            case 'avg':
                            case 'first':
                            case 'last':
                                $group_opt[$alias] = array
                                (
                                    '$'.$item[1] => '$'.$column,
                                );
                                break;
                            case 'addToSet':
                            case 'concat':
                                $group_opt[$alias] = array
                                (
                                    '$addToSet' => '$'.$column,
                                );
                                break;
                            case 'sum':
                                $group_opt[$alias] = array
                                (
                                    '$sum' => isset($item[2])?$item[2]:'$'.$column,
                                );
                                break;
                        }
                    }

                    $ops[] = array
                    (
                        '$group' => $group_opt,
                    );
                    $last_query .= '{$group:'.json_encode($group_opt);

                    if (isset($options['sort']) && $options['sort'])
                    {
                        $ops[]['$sort'] = $options['sort'];
                        $last_query .= ',$sort:'.json_encode($options['sort']);
                    }

                    if (isset($options['skip']) && $options['skip']>0)
                    {
                        $ops[]['$skip'] = $options['skip'];
                        $last_query .= ',$skip:'.$options['skip'];
                    }

                    if (isset($options['limit']) && $options['limit']>0)
                    {
                        $ops[]['$limit'] = $options['limit'];
                        $last_query .= ',$limit:'.$options['limit'];
                    }

                    $last_query .= '}';
                    $last_query .= ')';

                    $result = $connection->selectCollection($tablename)->aggregate($ops);

                    // 兼容不同版本的aggregate返回
                    if ($result && ($result['ok']==1||!isset($result['errmsg'])))
                    {
                        if ($result['ok']==1 && is_array($result['result']))$result = $result['result'];
                        if ($have_dot)foreach ($result as &$item)
                        {

                        	// 处理 _ID 字段
                        	if (is_array($item['_id']))foreach ($item['_id'] as $k=>$v)
                        	{
                        	    if (false!==strpos($k, '->'))
                        	    {
                        	        $item['_id'][str_replace('->', '.', $k)] = $v;
                        	        unset($item['_id'][$k]);
                        	    }
                        	}

                        	// 处理 select 的字段
                            foreach ($item as $k=>$v)
                            {
                                if (false!==strpos($k,'->'))
                                {
                                    $item[str_replace('->','.',$k)] = $v;
                                    unset($item[$k]);
                                }
                            }
                        }
                        if ($options['total_count'])
                        {
                            foreach ($result as &$item)
                            {
                                $item['total_count'] = $item['_count'];
                            }
                        }
                        $count = count($result);

                        $rs = new Database_Driver_Mongo_Result(new ArrayIterator($result), $options, $as_object ,$this->config);
                    }
                    else
                    {
                        throw new Exception($result['errmsg'].'.query:'.$last_query);
                    }
                }
                else
                {
                    $last_query = 'db.'.$tablename.'.find(';
                    $last_query .= $options['where']?json_encode($options['where']):'{}';
                    $last_query .= $options['select']?','.json_encode($options['select']):'';
                    $last_query .= ')';

                    $result = $connection->selectCollection($tablename)->find($options['where'],(array)$options['select']);

                    if(IS_DEBUG && $is_sql_debug)
                    {
                        $explain = $result->explain();
                        $count = $result->count();
                    }

                    if ($options['total_count'])
                    {
                        $last_query .= '.count()';
                        $result = $result->count();
                        # 仅统计count
                        $rs = new Database_Driver_Mongo_Result(new ArrayIterator(array(array('total_row_count'=>$result))), $options, $as_object ,$this->config);
                    }
                    else
                    {
                        if ($options['sort'])
                        {
                            $last_query .= '.sort('.json_encode($options['sort']).')';
                            $result = $result->sort($options['sort']);
                        }

                        if ($options['skip'])
                        {
                            $last_query .= '.skip('.json_encode($options['skip']).')';
                            $result = $result->skip($options['skip']);
                        }

                        if ($options['limit'])
                        {
                            $last_query .= '.limit('.json_encode($options['limit']).')';
                            $result = $result->limit($options['limit']);
                        }

                        $rs = new Database_Driver_Mongo_Result($result, $options, $as_object ,$this->config);
                    }
                }

                break;
            case 'UPDATE':
                $result = $connection->selectCollection($tablename)->update($options['where'] , $options['data'] , $options['options']);
                $count = $rs = $result['n'];
                $last_query = 'db.'.$tablename.'.update('.json_encode($options['where']).','.json_encode($options['data']).')';
                break;
            case 'SAVE':
            case 'INSERT':
            case 'BATCHINSERT':
                $fun = strtolower($type);
                $result = $connection->selectCollection($tablename)->$fun($options['data'] , $options['options']);

                if ($type=='BATCHINSERT')
                {
                    $count = count($options['data']);
                    # 批量插入
                    $rs = array
                    (
                        '',
                        $count,
                    );
                }
                elseif (isset($result['data']['_id']) && $result['data']['_id'] instanceof MongoId)
                {
                    $count = 1;
                    $rs = array
                    (
                        (string)$result['data']['_id'] ,
                        1 ,
                    );
                }
                else
                {
                    $count = 0;
                    $rs = array
                    (
                        '',
                        0,
                    );
                }

                if ($type=='BATCHINSERT')
                {
                    $last_query = '';
                    foreach ($options['data'] as $d)
                    {
                        $last_query .= 'db.'.$tablename.'.insert('.json_encode($d).');'."\n";
                    }
                    $last_query = trim($last_query);
                }
                else
                {
                    $last_query = 'db.'.$tablename.'.'.$fun.'('.json_encode($options['data']).')';
                }
                break;
            case 'REMOVE':
                $result = $connection->selectCollection($tablename)->remove($options['where']);
                $rs = $result['n'];

                $last_query = 'db.'.$tablename.'.remove('.json_encode($options['where']).')';
                break;
            default:
                throw new Exception('不支持的操作类型');
        }
    }
    catch (Exception $e)
    {
        if(IS_DEBUG && isset($benchmark))
        {
            Core::debug()->profiler('sql')->stop();
        }

        throw $e;
    }

    $this->last_query = $last_query;

    # 记录调试
    if(IS_DEBUG)
    {
        Core::debug()->info($last_query,'MongoDB');

        if (isset($benchmark))
        {
            if ($is_sql_debug)
            {
                $data = array();
                $data[0]['db']              = $host['hostname'] . '/' . $this->config['connection']['database'] . '/';
                $data[0]['cursor']          = '';
                $data[0]['nscanned']        = '';
                $data[0]['nscannedObjects'] = '';
                $data[0]['n']               = '';
                $data[0]['millis']          = '';
                $data[0]['row']             = $count;
                $data[0]['query']           = '';
                $data[0]['nYields']         = '';
                $data[0]['nChunkSkips']     = '';
                $data[0]['isMultiKey']      = '';
                $data[0]['indexOnly']       = '';
                $data[0]['indexBounds']     = '';

                if ($explain)
                {
                    foreach ($explain as $k=>$v)
                    {
                        $data[0][$k] = $v;
                    }
                }

                $data[0]['query'] = $last_query;
            }
            else
            {
                $data = null;
            }

            Core::debug()->profiler('sql')->stop($data);
        }
    }

    return $rs;
}