Eloquent Query基于json动态查询

时间:2016-06-28 08:21:11

标签: php laravel

我想根据数据库中的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

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

谢谢!

4 个答案:

答案 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()的模型方法,或任何您感觉更好的方法来处理内部的所有条件。我试图在这里处理大多数条件,而不仅仅是单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:虽然它应该可行,但我没有测试它。

答案 3 :(得分:0)

最终这个想法是它自己的限制因素,因为存储的查询必须代表数据库的当前状态。这意味着这些查询的维护成本在数据存储时会很重要另一种方式 - 如果您将列birthday更改为date_of birth,则所有存储的查询都将中断。避免这种情况。

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