41

In L-4 it was simple:

$random_quote = Quotation::all()->random(1);

But now in L-5 not a single method described in this post is working: Laravel - Eloquent or Fluent random row

My view file just gets blank.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Peter
  • 2,634
  • 7
  • 32
  • 46

10 Answers10

47

These works but probably you didn't use the right namespace, just use the use statement at the top of your class name like this:

<?php namespace SomeNamespace;

use App\Quotation; // Says "Quotation.php" is in "App" folder (By default in L-5.0)

class someClass {
    //...
}

Then you may use in your method something like this:

// You may add: use DB; at the top to use DB instead of \DB
$random_quote = Quotation::orderBy(\DB::raw('RAND()'))->first();

Or this:

$random_quote = Quotation::orderByRaw("RAND()")->first();

Update (Since Laravel - 5.2):

$random_quote = Quotation::inRandomOrder()->first();
The Alpha
  • 143,660
  • 29
  • 287
  • 307
31

random() gives error in 5.2, so instead u can use inRandomOrder https://laravel.com/docs/5.2/queries#ordering-grouping-limit-and-offset ,

and it works on Eloquent like

Model::inRandomOrder()->first()
ctf0
  • 6,991
  • 5
  • 37
  • 46
  • 1
    Now **THIS** should be the accepted answer. It's not database-specific AND leverages the framework capabilities. +1 – mmieluch Aug 02 '16 at 12:14
26

Update for Laravel 5.4

New randomsorting in Laravel 5.4 ->inRandomOrder()->first()

Peter
  • 2,634
  • 7
  • 32
  • 46
  • This really helped me, I am having an issue though, I only want a quote and author to show on the page (which is happening) but the id related to each quote is also appearing, how do I exclude the id? – CodeConnoisseur May 22 '19 at 00:57
14

UPDATE FOR LARAVEL 5.3

I was happy to discover this is now a native query function! :D

The inRandomOrder method may be used to sort the query results randomly. For example, you may use this method to fetch a random user:

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

Unfortunately none of these answers make full use of Laravel 5's collections. If you came here from Google, like me, looking for a completely native solution please look below!

The Answer from The Alpha has the Database dependency flaw and Benjamin's, as he pointed out, may pose a problem when rows are removed in between. Highly unlikely, but still possible.

Here's a a one line solution to select random rows in Laravel 5+

// The setup
$numberOfRows = 4;
$models = Model::all(); // or use a ::where()->get();

// And the actual randomisation line
$randRows = $models->shuffle()->slice(0,numberOfRows);

Et voila - happy coding! Vote it up when you see it so it'll rise on the page :)

Stan Smulders
  • 6,079
  • 1
  • 27
  • 23
  • 4
    While this would definitely work, it's excessive to get all results of a table when you only want one row. If you have very large tables, it would slow down performance considerably. – Mike Stivala Oct 21 '15 at 19:36
  • Just use a ->take(100)? – Stan Smulders Oct 21 '15 at 19:40
  • 2
    Then you would only get a random row of the first 100 rows! – Mike Stivala Oct 22 '15 at 06:40
  • Alright, fair point! First do a ->count() and then generate a random integer between 1 and $count, then use that for a ::find() - problem solved, right? – Stan Smulders Oct 22 '15 at 07:33
  • 1
    Let's say you have 500 rows. You'd pick a record: mt_rand(1,500), and use find. Quotation::find(15). What if the row with id 15 has been deleted? So you know you have 500 rows, but what you do not know is if there is a record associated with every id between 1 and 500. – MetalFrog Nov 14 '15 at 01:30
12

The orderByRaw('RAND()') has 2 issues:

  1. It's MySQL-server dependant
  2. It can be slow on large tables (fetches all rows)

Here is the solution i used, which seems to be a bit better:

$cnt = $records->count();
if ($cnt == 0)
    return;

$randIndex = rand(0, $cnt-1);
$obj = $records->skip($randIndex)->take(1)->first();

EDIT: Please note that my solution may be a problem (crash if no luck) in case of parrallel requests to the database, if some records are deleted between the "count()" and the "skip()".

Benjamin Piette
  • 3,645
  • 1
  • 27
  • 24
8

I'd implement this a little differently, using Benjamin's idea. A Query Scope for this feels appropriate so it's reusable, and it falls into your normal Eloquent use.

Note: In Eloquent 5.2, there is built in support for global scopes.

I'm going to create a trait that models can utilize, but you can just add the scopeRandom method directly to your specific model.

/app/GlobalScopes.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

trait GlobalScopes
{
    public function scopeRandom($query){
        $totalRows = static::count() - 1;
        $skip = $totalRows > 0 ? mt_rand(0, $totalRows) : 0;

        return  $query->skip($skip)->take(1);
    }
}

Then, each model you want to utilize the global scopes, name the trait inside the class.

/app/Quotation.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Quotation extends Model
{
    use GlobalScopes;

    //...
}

In use:

$randomQuote = \Quotation::random()->first();
Community
  • 1
  • 1
MetalFrog
  • 9,943
  • 1
  • 22
  • 24
5

In Laravel 5.1 (and Laravel 5.2) there is a random method in the Collection class returned by the Eloquent builder.

https://laravel.com/docs/5.1/collections#available-methods

So your call

$random_quote = Quotation::all()->random(1);

or

$random_quote = Quotation::where('column', 'value')->get()->random(1);

should work properly.

fsavina
  • 370
  • 4
  • 10
  • 3
    `$r = Quotation::all()->random(1);` does work, but it does a `select * from quotations` first which... could be quite slow if there are many Quotations... – erapert Aug 24 '16 at 16:11
3

Laravel 5.4

1) if need one random model:

$object = Model::all()->random();

2) if need many random models:

$object = Model::all()->random($n); //$n - number of elements
                                    //$object - collection

Comment: Calling $collection->random(1) will now return a new collection instance with one item.This method will only return a single object if no arguments are supplied.

Doc ref: https://laravel.com/docs/5.4/collections#method-random

Evgeniy Miroshnichenko
  • 1,788
  • 2
  • 19
  • 30
  • This is correct answer from my point of view. The other ones work as well, but even with Laravel 6.x its the documented approach https://laravel.com/docs/6.x/collections – s1x Sep 16 '19 at 18:12
2
orderByRaw('RAND()')

Note: It will take in ram all the rows from the rest of the query, so if you have a large table whithout other filters in the same query it will give bad performances, otherwise this is your option

Luca C.
  • 11,714
  • 1
  • 86
  • 77
0

You can use the random() method, which "returns a random item from the collection":

Product::where('city_id', $discount->product->city)
        ->get()
        ->random(1);
Nimantha
  • 6,405
  • 6
  • 28
  • 69
OmidDarvishi
  • 558
  • 4
  • 8