Laravel: fila aleatoria elocuente o fluida


242

¿Cómo puedo seleccionar una fila aleatoria usando Eloquent o Fluent en el marco de Laravel?

Sé que al usar SQL, puede ordenar por RAND (). Sin embargo, me gustaría obtener la fila aleatoria sin contar el número de registros antes de la consulta inicial.

¿Algunas ideas?


No hay mejor manera de hacerlo sin ejecutar al menos dos consultas.
NARKOZ

Respuestas:


584

Laravel> = 5.2:

User::all()->random();
User::all()->random(10); // The amount of items you wish to receive

o

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

o para obtener el número específico de registros

//5 indicates the number of records
User::inRandomOrder()->limit(5)->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();

Consulte este artículo sobre filas aleatorias de MySQL. Laravel 5.2 es compatible con esto, para una versión anterior, no hay mejor solución que usar consultas RAW .

editar 1: como mencionó Double Gras, orderBy () no permite nada más que ASC o DESC desde este cambio. Actualicé mi respuesta en consecuencia.

edit 2: Laravel 5.2 finalmente implementa una función de contenedor para esto. Se llama inRandomOrder () .


81
Reemplace 'get' con 'first' si desea una sola fila.
Precio de Collin

14
para uso PostgreSQL'RANDOM()'
dwenaus

2
Advertencia: en grandes conjuntos de datos esto es muy lento, agregando alrededor de 900 ms para mí
S

3
¿Podemos paginar esto?
Irfandi D. Vendy

3
Puede, sin embargo, la clasificación será aleatoria en cada página nueva. Lo que no tiene sentido porque es esencialmente lo mismo que presionas F5.
aebersold

49

Esto funciona bien

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

También puede cambiar el argumento en función aleatoria para obtener más de un registro.

Nota: no se recomienda si tiene datos enormes, ya que esto buscará primero todas las filas y luego devolverá un valor aleatorio.


61
Una desventaja en cuanto al rendimiento es que se recuperan todos los registros.
Gras Double

3
aquí se llama al azar en el objeto de colección, no en la consulta sql. la función aleatoria se ejecuta en el lado php
astroanu

@astroanu Correcto, pero para completar esa colección, se consultan todas las filas.
MetalFrog

1
Podría estar equivocado, pero esto no parece funcionar cuando el parámetro pasado a la función aleatoria es el mismo que el tamaño de la colección.
Brynn Bateman el

Esto no es bueno ... De esta manera está recuperando todos los registros y obteniendo uno aleatorio. Si su tabla tiene demasiados registros, esto podría ser malo para su aplicación.
Anderson Silva

34

tl; dr: Actualmente está implementado en Laravel, ver "editar 3" a continuación.


Lamentablemente, a partir de hoy hay algunas advertencias con la ->orderBy(DB::raw('RAND()'))solución propuesta:

  • No es independiente de DB. por ejemplo, uso de SQLite y PostgreSQLRANDOM()
  • Peor aún, esta solución ya no es aplicable ya que este cambio :

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


editar: ahora puede usar el método orderByRaw () :->orderByRaw('RAND()') . Sin embargo, esto todavía no es independiente de DB.

FWIW, CodeIgniter implementa un especial RANDOM dirección de clasificación , que se reemplaza con la gramática correcta al generar la consulta. También parece ser bastante fácil de implementar. Parece que tenemos un candidato para mejorar Laravel :)

actualización: aquí está el problema sobre esto en GitHub, y mi solicitud de extracción pendiente .


editar 2: cortemos la persecución. Desde Laravel 5.1.18 puede agregar macros al generador 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();


Edición 3: ¡Finalmente! Desde Laravel 5.2.33 ( registro de cambios , PR # 13642 ) puede usar el método nativo inRandomOrder():

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

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

Debe cambiar el nombre de la macro 5.1 a inRandomOrder para que sea compatible con versiones anteriores;) detalles, detalles :)
Sander Visser

Eso es precisamente una cosa que hice mientras preparaba un proyecto 5.1 antes de migrarlo a 5.2.
Gras Double

Esta es una gran respuesta. Si pudiera favorecer una respuesta, ¡lo haría!
mwallisch

18

En laravel 4 y 5 el order_byse sustituye pororderBy

Entonces, debería ser:

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

Usuario :: orderBy (DB :: raw ('RAND ()')) -> get ();
Darius M.

1
Funciona gracias, pero ¿podría dar alguna información sobre cómo funciona?
alayli

¿Podrías ser un poco más específico? ¿Que tipo de informacion?
Teodor Talov


9

Para Laravel 5.2> =

usa el método Eloquent:

inRandomOrder()

El método inRandomOrder puede usarse para ordenar los resultados de la consulta al azar. Por ejemplo, puede usar este método para buscar un usuario aleatorio:

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

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


Curso :: inRandomOrder () -> take (20) -> get (); No funciona para mí: especificación de clasificación incorrecta en Find.php línea 219
MJ

1
Este es útil para fábricas modelo o siembra de db
Saleh Mahmood

8

También puede usar el método order_by con fluidez y elocuencia como:

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

Este es un uso un poco extraño, pero funciona.

Editar: como dijo @Alex, este uso es más limpio y también funciona:

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

3
esto también funciona y es un poco más limpio .. -> order_by (\ DB :: raw ('RAND ()'))
Alex Naspo


3

Puede usar fácilmente este comando:

// Pregunta: nombre del modelo
// tomar 10 filas de la base de datos en registros aleatorios ...

$questions = Question::orderByRaw('RAND()')->take(10)->get();

3

Prefiero especificar primero o fallar:

$collection = YourModelName::inRandomOrder()
  ->firstOrFail();

3

Laravel tiene un método incorporado para barajar el orden de los resultados.

Aquí hay una cita de la documentación:

shuffle()

El método aleatorio baraja aleatoriamente los elementos de la colección:

$collection = collect([1, 2, 3, 4, 5]);

$shuffled = $collection->shuffle();

$shuffled->all();

// [3, 2, 5, 1, 4] - (generated randomly)

Puedes ver la documentación aquí .


2

En su modelo agregue esto:

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;
}

luego en ruta / controlador

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

2

También hay whereRaw('RAND()')que hace lo mismo, a continuación, puede cadena ->get()o ->first()incluso volverse loco y añadir ->paginate(int).


0

Tengo una tabla con miles de registros, por lo que necesito algo rápido. Este es mi código para la fila pseudoaleatoria:

// 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(); 

El problema con esto es que si hay varias filas con identificadores mayores que $countsolo se recuperaría el primero de ellos, por lo que también sería más probable que se recupere que cualquier otra fila.
kemika
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.