Laravel - Fila casuale eloquente o fluente


242

Come posso selezionare una riga casuale usando Eloquent o Fluent nel framework Laravel?

So che usando SQL, puoi fare l'ordine per RAND (). Tuttavia, vorrei ottenere la riga casuale senza fare un conteggio sul numero di record prima della query iniziale.

Qualche idea?


Non esiste un modo migliore per farlo senza eseguire almeno due query.
NARKOZ,

Risposte:


587

Laravel> = 5.2:

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

o

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

o per ottenere il numero specifico di record

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

Controlla questo articolo sulle righe casuali di MySQL. Laravel 5.2 supporta questo, per la versione precedente, non esiste una soluzione migliore rispetto all'utilizzo di query RAW .

modifica 1: Come menzionato da Double Gras, orderBy () non consente nient'altro che ASC o DESC da questa modifica. Ho aggiornato la mia risposta di conseguenza.

modifica 2: Laravel 5.2 implementa finalmente una funzione wrapper per questo. Si chiama inRandomOrder () .


81
Sostituisci "get" con "first" se desideri una singola riga.
Collin Price,

14
per l'uso PostgreSQL'RANDOM()'
dwenaus

2
Attenzione: su set di dati di grandi dimensioni è molto lento, aggiungendo circa 900 ms per me
S ..

3
Possiamo impaginare questo?
Irfandi D. Vendy,

3
Puoi, tuttavia, l'ordinamento sarà casuale su ogni nuova pagina. Il che non ha senso perché è essenzialmente lo stesso che si preme F5.
aebersold,

49

Funziona bene,

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

puoi anche cambiare argomento in funzione casuale per ottenere più di un record.

Nota: sconsigliato se si dispone di dati enormi, in quanto verranno prima recuperate tutte le righe e quindi restituito un valore casuale.


61
Un aspetto negativo delle prestazioni è che tutti i record vengono recuperati.
Gras Double

3
qui viene chiamato random sull'oggetto collection non sulla query sql. la funzione casuale viene eseguita dal lato php
astroanu,

@astroanu Giusto, ma per popolare quella raccolta, vengono interrogate tutte le righe.
MetalFrog,

1
Potrei sbagliarmi, ma questo non sembra funzionare quando il parametro passato alla funzione casuale è uguale alla dimensione della raccolta.
Brynn Bateman,

Questo non va bene ... In questo modo stai recuperando tutti i record e ne ottieni uno casuale. Se il tuo tavolo ha troppi record, questo potrebbe essere negativo per la tua app.
Anderson Silva,

34

tl; dr: oggi è implementato in Laravel, vedi "modifica 3" di seguito.


Purtroppo, ad oggi ci sono alcuni avvertimenti con la ->orderBy(DB::raw('RAND()'))soluzione proposta:

  • Non è indipendente dal DB. es. uso di SQLite e PostgreSQLRANDOM()
  • Ancora peggio, questa soluzione non è più applicabile dal momento che questa modifica :

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


edit: Ora è possibile utilizzare l'orderByRaw () metodo: ->orderByRaw('RAND()'). Tuttavia, questo non è ancora DB-agnostico.

FWIW, CodeIgniter implementa una RANDOMdirezione di ordinamento speciale , che viene sostituita con la grammatica corretta durante la creazione di query. Inoltre sembra essere abbastanza facile da implementare. Sembra che abbiamo un candidato per migliorare Laravel :)

aggiornamento: ecco il problema al riguardo su GitHub e la mia richiesta pull in sospeso .


modifica 2: tagliamo l'inseguimento. Da Laravel 5.1.18 è possibile aggiungere macro al generatore di query:

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


modifica 3: Finalmente! Dal momento che laravel 5.2.33 ( changelog , PR # 13642 ) è possibile utilizzare il metodo nativo inRandomOrder():

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

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

Dovresti cambiare il nome della macro 5.1 in inRandomOrder in modo che sia compatibile in avanti;) dettagli, dettagli :)
Sander Visser

Questa è esattamente una cosa che ho fatto durante la preparazione di un progetto 5.1 prima di migrarlo a 5.2.
Gras Double,

Questa è un'ottima risposta. Se potessi preferire una risposta, lo farei!
mwallisch,

18

In laravel 4 e 5 la order_byè sostituito dalorderBy

Quindi, dovrebbe essere:

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

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

1
Funziona grazie, ma potresti darci alcune informazioni su come funziona?
alayli,

potresti essere un po 'più specifico? Che tipo di informazioni?
Teodor Talov,


9

Per Laravel 5.2> =

usa il metodo Eloquent:

inRandomOrder()

Il metodo inRandomOrder può essere utilizzato per ordinare i risultati della query in modo casuale. Ad esempio, è possibile utilizzare questo metodo per recuperare un utente casuale:

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

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


Corso :: inRandomOrder () -> prendere (20) -> get (); Non funziona per me - specifica di ordinamento errata nella riga Find.php 219
MJ

1
Questo è utile per le fabbriche modello o la semina db
Saleh Mahmood,

8

Puoi anche usare il metodo order_by con fluente ed eloquente come:

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

Questo è un po 'strano, ma funziona.

Modifica: come diceva @Alex, questo utilizzo è più pulito e funziona anche:

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

3
funziona anche ed è un po 'più pulito .. -> order_by (\ DB :: raw (' RAND () '))
Alex Naspo,


3

Puoi facilmente usare questo comando:

// Domanda: nome del modello
// prende 10 righe dal DB nei record shuffle ...

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

3

Preferisco specificare prima o non riesco:

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

3

Laravel ha un metodo integrato per mescolare l'ordine dei risultati.

Ecco un preventivo dalla documentazione:

shuffle()

Il metodo shuffle mescola casualmente gli oggetti nella raccolta:

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

$shuffled = $collection->shuffle();

$shuffled->all();

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

Puoi vedere la documentazione qui .


2

Al tuo modello aggiungi questo:

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

quindi al percorso / controller

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

2

C'è anche whereRaw('RAND()'), che fa la stessa cosa, si può quindi catena ->get()o ->first()o anche impazzire e aggiungere ->paginate(int).


0

Ho una tabella con migliaia di record, quindi ho bisogno di qualcosa di veloce. Questo è il mio codice per la riga pseudo casuale:

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

Il problema è che se ci sono più righe con ID maggiori di $countsolo il primo di questi verrebbero mai recuperati, e quindi sarebbe anche più probabile che vengano recuperati rispetto a qualsiasi altra riga.
kemika,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.