Laravel - Baris acak Fasih atau Lancar

242

Bagaimana saya bisa memilih baris acak menggunakan Eloquent atau Fluent in Laravel framework?

Saya tahu bahwa dengan menggunakan SQL, Anda dapat melakukan pemesanan dengan RAND (). Namun, saya ingin mendapatkan baris acak tanpa menghitung jumlah rekaman sebelum kueri awal.

Ada ide?

DigitalWM
sumber
Tidak ada cara terbaik untuk melakukan ini tanpa menjalankan setidaknya dua permintaan.
NARKOZ

Jawaban:

587

Laravel> = 5.2:

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

atau

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

atau untuk mendapatkan jumlah catatan spesifik

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

Lihat artikel ini di baris acak MySQL. Laravel 5.2 mendukung ini, untuk versi yang lebih lama, tidak ada solusi yang lebih baik daripada menggunakan RAW Queries .

sunting 1: Seperti yang disebutkan oleh Double Gras, orderBy () tidak mengizinkan apa pun selain ASC atau DESC sejak perubahan ini . Saya memperbarui jawaban saya sesuai.

sunting 2: Laravel 5.2 akhirnya mengimplementasikan fungsi wrapper untuk ini. Ini disebut inRandomOrder () .

aebersold
sumber
81
Ganti 'dapatkan' dengan 'pertama' jika Anda ingin satu baris.
Harga Collin
14
untuk penggunaan PostgreSQL'RANDOM()'
dwenaus
2
Peringatan: pada dataset besar ini sangat lambat, menambahkan sekitar 900 ms untuk saya
S ..
3
Bisakah kita membuat paginasi ini?
Irfandi D. Vendy
3
Anda bisa, namun penyortirannya akan acak pada setiap halaman baru. Yang tidak masuk akal karena pada dasarnya sama dengan Anda menekan F5.
aebersold
49

Ini berfungsi dengan baik,

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

Anda juga dapat mengubah argumen dalam fungsi acak untuk mendapatkan lebih dari satu catatan.

Catatan: tidak disarankan jika Anda memiliki data besar karena ini akan mengambil semua baris terlebih dahulu dan kemudian mengembalikan nilai acak.

jantan
sumber
61
Kelemahan kinerja-bijaksana adalah bahwa semua catatan diambil.
Gras Double
3
di sini acak dipanggil pada objek koleksi bukan kueri sql. fungsi acak dijalankan di sisi php
astroanu
@astroanu Benar, tetapi untuk mengisi koleksi itu, semua baris dipertanyakan.
MetalFrog
1
Saya bisa saja salah, tetapi ini tampaknya tidak berfungsi ketika parameter yang dilewatkan ke fungsi acak sama dengan ukuran koleksi.
Brynn Bateman
Ini tidak baik ... Dengan cara ini Anda mengambil semua catatan dan mendapatkan yang acak. Jika tabel Anda memiliki terlalu banyak catatan, ini bisa berakibat buruk untuk aplikasi Anda.
Anderson Silva
34

tl; dr: Saat ini diterapkan ke Laravel, lihat "sunting 3" di bawah.


Sayangnya, sampai hari ini ada beberapa peringatan dengan ->orderBy(DB::raw('RAND()'))solusi yang diusulkan:

  • Itu bukan DB-agnostik. misalnya penggunaan SQLite dan PostgreSQLRANDOM()
  • Lebih buruk lagi, solusi ini tidak berlaku lagi sejak perubahan ini :

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


sunting: Sekarang Anda dapat menggunakan metode orderByRaw () :->orderByRaw('RAND()') . Namun ini masih bukan DB-agnostik.

FWIW, CodeIgniter mengimplementasikan khusus RANDOM arah penyortiran , yang diganti dengan tata bahasa yang benar ketika membangun kueri. Juga tampaknya cukup mudah diimplementasikan. Sepertinya kami memiliki kandidat untuk meningkatkan Laravel :)

pembaruan: inilah masalah tentang ini di GitHub, dan permintaan tarik saya yang tertunda .


edit 2: Mari kita memotong pengejaran. Karena Laravel 5.1.18 Anda dapat menambahkan makro ke pembuat kueri:

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

Pemakaian:

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

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


edit 3: Akhirnya! Karena Laravel 5.2.33 ( changelog , PR # 13642 ) Anda dapat menggunakan metode asli inRandomOrder():

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

DB::table('users')->where('active', 1)->inRandomOrder()->limit(10)->get();
Gras Double
sumber
Anda harus mengubah nama makro 5.1 menjadi inRandomOrder sehingga kompatibel;) detail, detail :)
Sander Visser
Itulah satu hal yang saya lakukan ketika menyiapkan proyek 5.1 sebelum memindahkannya ke 5.2.
Gras Double
Ini jawaban yang bagus. Jika saya dapat menemukan jawaban, saya akan melakukannya!
mwallisch
18

Dalam LARAVEL 4 dan 5 yang order_bydigantikan olehorderBy

Jadi, seharusnya:

User::orderBy(DB::raw('RAND()'))->get();
Teodor Talov
sumber
Pengguna :: orderBy (DB :: raw ('RAND ()')) -> get ();
Darius
1
Ini berfungsi, terima kasih, tetapi bisakah Anda memberikan informasi bagaimana ini bekerja?
alayli
Bisakah kamu sedikit lebih spesifik? Informasi seperti apa?
Teodor Talov
17

Anda bisa menggunakan :

ModelName::inRandomOrder()->first();
simhumileco
sumber
9

Untuk Laravel 5.2> =

gunakan metode Eloquent:

inRandomOrder()

Metode inRandomOrder dapat digunakan untuk mengurutkan hasil permintaan secara acak. Misalnya, Anda dapat menggunakan metode ini untuk mengambil pengguna acak:

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

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

Manuel Azar
sumber
Kursus :: inRandomOrder () -> take (20) -> get (); Tidak berfungsi untuk saya - spesifikasi pengurutan buruk di baris Find.php 219
MJ
1
Yang ini berguna untuk pabrik model atau penyemaian db
Saleh Mahmood
8

Anda juga dapat menggunakan metode order_by dengan fasih dan fasih seperti:

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

Ini sedikit aneh penggunaannya, tetapi berhasil.

Sunting: Seperti yang dikatakan @Alex, penggunaan ini lebih bersih dan juga berfungsi:

Posts::where_status(1)->order_by(DB::raw('RAND()'));
Bilal Gultekin
sumber
3
ini berfungsi juga dan sedikit lebih bersih .. -> order_by (\ DB :: raw ('RAND ()'))
Alex Naspo
3

Gunakan fungsi Laravel

ModelName::inRandomOrder()->first();
Kamlesh Paul
sumber
3

Anda dapat dengan mudah menggunakan perintah ini:

// Pertanyaan: nama Model
// ambil 10 baris dari DB Dalam catatan acak ...

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

Saya lebih memilih untuk menentukan dulu atau gagal:

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

Laravel memiliki metode bawaan untuk mengocok urutan hasil.

Berikut ini kutipan dari dokumentasi:

shuffle()

Metode acak mengacak item dalam koleksi:

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

$shuffled = $collection->shuffle();

$shuffled->all();

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

Anda dapat melihat dokumentasinya di sini .

AlmostPitt
sumber
2

Pada model Anda, tambahkan ini:

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

kemudian pada route / controller

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

Ada juga whereRaw('RAND()')yang melakukan hal yang sama, maka Anda dapat rantai ->get()atau ->first()atau bahkan gila dan menambahkan ->paginate(int).

ctf0
sumber
0

Saya punya meja dengan ribuan catatan, jadi saya butuh sesuatu dengan cepat. Ini adalah kode saya untuk baris acak semu:

// 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(); 
Krzysztof Chełchowski
sumber
Masalah dengan ini adalah bahwa jika ada beberapa baris dengan id lebih besar dari $counthanya yang pertama yang akan diambil, dan itu juga akan lebih mungkin untuk diambil daripada baris lainnya.
kemika