2016-06-28 60 views
1

我想根据数据库中的有效负载(json)动态查询。基于json动态查询

例子:

$data = [{"key":"age","relation":">","value":"15"},{"operator":"OR"},{"key":"age","relation":"<=","value":"20"}] 

我想基于该有效载荷做查询。

现在我在做什么是:

$query = User::all(); 
$payload = json_decode($data, true); 
foreach($payload as $value){ 
    if ($value['key'] == 'age') { 
       $query = $query->where('birthday', $value['relation'], Carbon::now()->subYears($value['age'])->format('Y-m-d');) 
      } 

    if($value['key'] == 'gender'{ 
     $query = $query->where('gender', $value['relation'], $value['gender']); 
    } 
} 

问题是,是的,它可以工作,但我不认为这是最好的办法。我没有得到任何解决方案来使用“操作员”键。操作员的使用是将where更改为orWhere

任何解决方案或提示,使它像这样动态调用?我希望我的专栏在数据库整洁而简单。我只能这样想。

谢谢!

+0

如果您希望查询简单直接,那么在这种情况下您应该更愿意编写原始查询。这将会更加干净。 –

+0

@VishalSh谢谢你的建议。在我的情况下原始查询的任何示例? – ssuhat

+0

@SSuhat你是否发送'AND'运算符以及有效载荷? – z3r0ck

回答

1

你可以这样做原始查询。

$data = '[{"key":"age","relation":">","value":"15"},{"operator":"OR"},{"key":"age","relation":"<=","value":"20"}]'; 

$query = "SELECT * FROM tablename WHERE"; 

$payload = json_decode($data, true); 

foreach ($payload as $value) { 
    if (isset($value['operator'])) { 
     $query .= " " . $value['operator']; 
    } else { 
     if ($value['key'] == 'age') { 
      $query .= " 'birthday' " . $value['relation'] . " " . Carbon::now()->subYears($value['value'])->format('Y-m-d'); 
     } 

     if ($value['key'] == 'gender') { 
      $query .= " 'gender' " . $value['relation'] . " " . $value['gender']; 
     } 
    } 
} 

这导致这样的查询:

SELECT * FROM tablename WHERE 'birthday' > 2001-07-02 OR 'birthday' <= 1996-07-02 

当然,你可以使用printf()进行格式化,使该清洁剂在其他一些方式,但是这将让你开始希望。

+0

嗨..但是,如果'json数组'是**空**。这意味着如果没有给定条件,那么查询将是'select * from tablename where',这个查询是否会运行..? – Avishek

+0

一个简单的'if'检查可以实现这一点。正如我所提到的,这只是一个起点。 – z3r0ck

0

最终这个想法是它自己的限制器,因为存储的查询将不得不代表数据库的当前状态。这意味着,在数据以不同方式存储时,这些查询的维护成本将非常高 - 如果将列birthday更改为date_of birth,则所有存储的查询都将中断。避免这种情况。

相反,通过使用Query ScopesRelationships将查询存储在模型上可以更好地实现此目标。如果您仍然需要一个动态的请求列表,您可以存储与查询关联的关键字并在其中循环。

1

您可以使用一个变量的函数名来添加orWhere逻辑:

$query = User::all(); 
$payload = json_decode($data, true); 
$function = 'where'; 
foreach($payload as $value){ 
    if(isset($value['operator'])){ 
    $function = $value['operator'] == 'OR' ? 'orWhere' : 'where'; 
    } else { 
    if ($value['key'] == 'age') { 
     $query = $query->$function('birthday', $value['relation'], Carbon::now()->subYears($value['age'])->format('Y-m-d');) 
    } else { 
     $query = $query->$function($value['key'], $value['relation'], $value['value']); 
    } 
    } 
} 

只要你的JSON数据不匹配您的数据库(即JSON有age但是数据库具有birthday。)将无法避免使用if/else语句。该定制逻辑将不得不保持。

1

遇到这个问题,我会用Local Query Scopes去。在这种方法中,您可以创建一个名为scopeJson()的模型方法或任何您感觉更好的方法来处理里面的所有条件。我试图在这里处理大多数情况,不仅是单一的whereorWhere。我假设您的有效载荷一次只包含一个构建器。

public function scopeJson($query, $json) 
{ 
    $wheres = [ 
     'between' => ['whereBetween', 'not' => 'whereNotBetween'], 
     'null' => ['whereNull', 'not' => 'whereNotNull'], 
     'or'  => ['orWhere', 'not' => 'orWhereNot'], 
     'in'  => ['whereIn', 'not' => 'whereNotIn'], 
     'and'  => ['where', 'not' => 'orWhereNot'], 
     'raw'  => 'whereRaw' 
    ]; 

    $builder = json_decode($json); 

    if (count($builder) > 0) { 
     $query->where(
      $builder[0]->key, 
      $builder[0]->relation, 
      $builder[0]->value 
     ); 

     // notBetween, notNull, notOr, notIn, notAnd 
     if (stripos($builder[1]->operator, 'not') !== false) { 
      $whereCondition = $wheres[strtolower(substr($builder[1]->operator, 3))]['not']; 
     } else { 
      $whereCondition = $wheres[strtolower($builder[1]->operator)]; 
     } 

     if (count($builder[2]) == 3) { 
      if ($whereCondition == 'whereRaw') { 
       $query->$whereCondition(implode(" ", $builder[2])); 
      } else { 
       // where, whereNot 
       $query->$whereCondition(
        $builder[2]->key, 
        $builder[2]->relation, 
        $builder[2]->value 
       ); 
      } 
     } elseif (count($builder[2]) == 2) { 
      // whereBetween, whereNotBetween, where, whereNot 
      $query->$whereCondition(
       $builder[2]->key, 
       $builder[2]->value 
      ); 
     } elseif (count($builder[2]) == 1) { 
      // whereNull, whereNotNull, whereRaw 
      $query->$whereCondition(
       $builder[2]->key ?? $builder[2]->value // PHP 7.0 Null Coalescing Operator 
      ); 
     } 
    } 
    return $query; 
} 

如果此方法是您的用户模型中定义的,那么你可以使用这种方式:

$users = User::json($data)->get(); 

PS:虽然它应该工作,我没有测试它。