Laravel – Fila aleatória elocuente ou fluente

Como posso selecionar uma linha aleatória usando Eloquent ou Fluent no framework Laravel?

Eu sei que ao usar o SQL, você pode fazer o pedido por RAND (). No entanto, eu gostaria de obter a linha aleatória sem fazer uma contagem no número de registros antes da consulta inicial.

Alguma ideia?

Laravel> = 5,2:

User::inRandomOrder()->get(); 

Laravel 4.2.7 – 5.1:

 User::orderByRaw("RAND()")->get(); 

Laravel 4.0 – 4.2.6:

 User::orderBy(DB::raw('RAND()'))->get(); 

Laravel 3:

 User::order_by(DB::raw('RAND()'))->get(); 

Verifique este artigo em linhas aleatórias do MySQL. O Laravel 5.2 suporta isso, para uma versão mais antiga, não há solução melhor, em seguida, usando consultas RAW .

editar 1: conforme mencionado pelo Double Gras, orderBy () não permite nada mais do que ASC ou DESC desde essa mudança. Eu atualizei minha resposta de acordo.

edite 2: Laravel 5.2 finalmente implementa uma function de wrapper para isso. É chamado inRandomOrder () .

Isso funciona muito bem,

 $model=Model::all()->random(1); 

Você também pode alterar argumentos em function aleatória para obter mais de um registro.

Nota: não recomendado se você tiver dados enormes, pois isso buscará todas as linhas primeiro e, em seguida, retornará o valor random.

Infelizmente, a partir de hoje existem algumas advertências com a solução proposta ->orderBy(DB::raw('RAND()')) :

  • Não é DB-agnóstico. Por exemplo, SQLite e PostgreSQL usam RANDOM()
  • Pior ainda, esta solução não é mais aplicável desde essa mudança :

    $direction = strtolower($direction) == 'asc' ? 'asc' : 'desc';

editar: agora você pode usar o método orderByRaw () : ->orderByRaw('RAND()') . No entanto, isso ainda não é DB-agnóstico.

FWIW, CodeIgniter implementa uma direção de sorting especial RANDOM , que é substituída pela gramática correta ao criar uma consulta. Também parece ser bastante fácil de implementar. Parece que temos um candidato para melhorar Laravel 🙂

atualização: aqui está a questão sobre isso no GitHub e meu pedido de tração pendente.

Edite 2: Vamos cortar a perseguição. Desde Laravel 5.1.18, você pode adicionar macros ao construtor de consultas:

 use Illuminate\Database\Query\Builder; Builder::macro('orderByRandom', function () { $randomFunctions = [ 'mysql' => 'RAND()', 'pgsql' => 'RANDOM()', 'sqlite' => 'RANDOM()', 'sqlsrv' => 'NEWID()', ]; $driver = $this->getConnection()->getDriverName(); return $this->orderByRaw($randomFunctions[$driver]); }); 

Uso:

 User::where('active', 1)->orderByRandom()->limit(10)->get(); DB::table('users')->where('active', 1)->orderByRandom()->limit(10)->get(); 

editar 3: Finalmente! Desde Laravel 5.2.33 ( changelog , PR # 13642 ), você pode usar o método nativo inRandomOrder() :

 User::where('active', 1)->inRandomOrder()->limit(10)->get(); DB::table('users')->where('active', 1)->inRandomOrder()->limit(10)->get(); 

Em Laravel 4 e 5, o order_by é substituído por orderBy

Então, deve ser:

 User::orderBy(DB::raw('RAND()'))->get(); 

Você também pode usar o método order_by com fluente e eloquent como:

 Posts::where_status(1)->order_by(DB::raw(''),DB::raw('RAND()')); 

Este é um pouco de uso estranho, mas funciona.

Edit: Como o @Alex disse, esse uso é mais limpo e também funciona:

 Posts::where_status(1)->order_by(DB::raw('RAND()')); 

Para Laravel 5.2> =

use o método Eloquent:

 inRandomOrder() 

O método inRandomOrder pode ser usado para classificar aleatoriamente os resultados da consulta. Por exemplo, você pode usar esse método para buscar um usuário random:

 $randomUser = DB::table('users') ->inRandomOrder() ->first(); 

docs: https://laravel.com/docs/5.2/queries#ordering-grouping-limit-and-offset

No seu modelo, adicione isso:

 public function scopeRandomize($query, $limit = 3, $exclude = []) { $query = $query->whereRaw('RAND()< (SELECT ((?/COUNT(*))*10) FROM `products`)', [$limit])->orderByRaw('RAND()')->limit($limit); if (!empty($exclude)) { $query = $query->whereNotIn('id', $exclude); } return $query; } 

então na rota / controlador

 $data = YourModel::randomize(8)->get(); 

há também whereRaw('RAND()') que faz o mesmo, então você pode encadear ->get() ou ->first() ou mesmo ficar louco e adicionar ->paginate(int)

Tenho mesa com milhares de registros, então preciso de algo rápido. Este é o meu código para a linha pseudo-aleatória:

 // count all rows with flag active = 1 $count = MyModel::where('active', '=', '1')->count(); // get random id $random_id = rand(1, $count - 1); // get first record after random id $data = MyModel::where('active', '=', '1')->where('id', '>', $random_id)->take(1)->first(); 

Você pode usar:

 ModelName::inRandomOrder()->first(); 

Você pode usar facilmente este comando // Pergunta: nome do modelo // pegue 10 linhas do db nos registros randoms …

$ question = Question :: orderByRaw (‘RAND ()’) -> take (10) -> get ();