我想根据数据库中的payload(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']);
}
}
问题是肯定它可行,但我不认为这是最佳方法。我没有得到任何解决方案来使用&#34;运营商&#34;键。运营商的使用方法是将where
更改为orWhere
。
任何解决方案或提示让它像这样动态调用?我希望我的数据库整洁而简单。我只能这样想。
谢谢!
答案 0 :(得分: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()
进行格式化,并以其他方式使其更清洁,但这将使您有希望开始。
答案 1 :(得分:1)
您可以使用变量函数名称添加 ServiceCall dialog = service.updateDialog("ID", new File("file/template.xml"));
System.out.println(dialog.execute());
逻辑:
orWhere
只要您的json数据与您的数据库不匹配(即json有$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']);
}
}
}
但数据库有age
),您将无法避免使用if / else声明。该定制逻辑必须保留。
答案 2 :(得分:1)
遇到这个问题,我会选择Local Query Scopes。在这种方法中,您可以创建一个名为scopeJson()
的模型方法,或任何您感觉更好的方法来处理内部的所有条件。我试图在这里处理大多数条件,而不仅仅是单where
和orWhere
。我假设您的有效负载一次只包含一个构建器。
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:虽然它应该可行,但我没有测试它。
答案 3 :(得分:0)
最终这个想法是它自己的限制因素,因为存储的查询必须代表数据库的当前状态。这意味着这些查询的维护成本在数据存储时会很重要另一种方式 - 如果您将列birthday
更改为date_of birth
,则所有存储的查询都将中断。避免这种情况。
相反,通过使用Query Scopes和Relationships将查询存储在模型上可以更好地实现此目标。如果您仍然需要动态的请求列表,则可以存储与查询关联的关键字并循环访问它们。