Thinkphp uses mongodb database to implement multi condition query method

  • 2021-07-04 21:40:55
  • OfStack

One project uses the mongodb database, The query criteria are and and or, According to the official manual of Thinkphp, Using compound query (_ complex), getLastSql output query statement, found that the query condition is empty. Using string mode query (_ string), request string query (_ query) can not meet the requirements. It is estimated that there are not many users using mongodb, and thinkphp official support for this aspect is not enough. Open mongodb driver of thinkphp, Thinkphp/Extend/Driver/Db/DbMongo. class. php, find protected function parseThinkWhere ($key, $val), and you can find that there is no _ complex in switch, that is,


case '_complex':// Compound query
             $arr   = array();
             foreach ($val as $nkey=>$nval){
              if( strpos($nkey,'_')!=0)
              {
               $parseArr=$this->parseWhereItem($nkey,$nval);
               // Convert to an object
               $obj=new stdClass();
               foreach ($parseArr as $pkey=>$pval)
               {
                $obj->$pkey=$pval;
               }
               array_push($arr, $obj);
              }
             }
             if(isset($val['_logic']) && strtolower($val['_logic']) == 'or' ) {
              unset($val['_logic']);
              $query['$or']   =  $arr;
             }
             break;

The reason for converting to an object here is to use thinkphp to use the json_encode function to generate a query statement, but if the array element has key, the json_encode function will convert the array to an object form, which mongodb cannot recognize. Because only or is used at present, the code only deals with or.
In addition, I found an BUG (I don't know if it counts). In the parseWhere method:


foreach ($where as $key=>$val){
            if('_id' != $key && 0===strpos($key,'_')) {
                // Parsing special conditional expressions
                // Original $query=$this->parseThinkWhere($key,$val);
                $query   = array_merge($query,$this->parseThinkWhere($key,$val));
            }else{
                // Security Filtering of Query Fields
                if(!preg_match('/^[A-Z_\|\&\-.a-z0-9]+$/',trim($key))){
                    throw_exception(L('_ERROR_QUERY_').':'.$key);
                }
                $key = trim($key);
                if(strpos($key,'|')) {
                    $array   =  explode('|',$key);
                    $str   = array();
                    foreach ($array as $k){
                        $str[]   = $this->parseWhereItem($k,$val);
                    }
                    $query['$or'] =    $str;
                }elseif(strpos($key,'&')){
                    $array   =  explode('&',$key);
                    $str   = array();
                    foreach ($array as $k){
                        $str[]   = $this->parseWhereItem($k,$val);
                    }
                    $query   = array_merge($query,$str);
                }else{
                    $str   = $this->parseWhereItem($key,$val);
                    $query   = array_merge($query,$str);
                }
            }
        }

When parsing a special conditional expression, the source code is $query = $this- > parseThinkWhere ($key, $val); When the special expression is not the first element in the where array, there is an error, and the $query array obtained by the code in else is gone.


Related articles: