2016-06-28 2 views
1

Я хочу запросить динамически на основе полезной нагрузки (json) из базы данных.Eloquent Query Динамически основанный на 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']); 
    } 
} 

Проблема да он может работать, но я не думаю, что это лучший подход. Я не получаю никакого решения использовать ключ «operator». Использование оператора должно изменить where на orWhere.

Любое решение или советы, чтобы заставить его динамически звонить так. Я хочу, чтобы моя колонка в DB была аккуратной и простой. Я могу думать только так.

Спасибо!

+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 array' ** пуст **. Это означает, что если условие не задано, тогда запрос будет 'select * from tablename where', будет ли этот запрос запущен.? – Avishek

+0

Простая проверка 'if' может это сделать. Как я уже говорил, это всего лишь отправная точка. – z3r0ck

0

В конечном итоге эта идея представляет собой собственный ограничитель, поскольку хранящиеся запросы должны представлять текущее состояние базы данных. Это означает, что стоимость обслуживания этих запросов будет значительной, если данные хранятся по-другому - если вы изменили столбец birthday на date_of birth, все ваши сохраненные запросы будут ломаться. Избегайте этого.

Вместо этого эта цель лучше достигается путем хранения запросов на модели с использованием Query Scopes и Relationships. Если вам по-прежнему нужен динамический список запросов, вы можете хранить ключевые слова, связанные с запросами, и прокручивать их.

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() или с тем, что вам будет лучше, чтобы сменить все условия внутри. Я старался обрабатывать большинство условий здесь не только 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: Несмотря на то, что должно работать, я не проверял.