ChatGPT解决这个技术问题 Extra ChatGPT

Laravel - Eloquent or Fluent random row

How can I select a random row using Eloquent or Fluent in Laravel framework?

I know that by using SQL, you can do order by RAND(). However, I would like to get the random row without doing a count on the number of records prior to the initial query.

Any ideas?

There is no best way to do this without executing at least two queries.

D
D Malan

Laravel >= 5.2:

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

or to get the specific number of records

// 5 indicates the number of records
User::inRandomOrder()->limit(5)->get();
// get one random record
User::inRandomOrder()->first();

or using the random method for collections:

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

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

Check this article on MySQL random rows. Laravel 5.2 supports this, for older version, there is no better solution then using RAW Queries.

edit 1: As mentioned by Double Gras, orderBy() doesn't allow anything else then ASC or DESC since this change. I updated my answer accordingly.

edit 2: Laravel 5.2 finally implements a wrapper function for this. It's called inRandomOrder().


Replace 'get' with 'first' if you want a single row.
for PostgreSQL use 'RANDOM()'
Warning: on large datasets this is very slow, adding around 900 ms for me
Can we paginate this?
You can, however the sorting will be random on every new page. Which makes no sense because it's essentially the same as you press F5.
Y
Yevgeniy Afanasyev

This works just fine,

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

you can also change argument in random function to get more than one record.

Note: not recommended if you have huge data as this will fetch all rows first and then returns random value.


A performance-wise downside is that all the records are retrieved.
here random is called on the collection object not the sql query. the random function is run on php side
@astroanu Right, but to populate that collection, all rows are queried.
I could be wrong, but this doesn't seem to work when the parameter passed to the random function is the same as the size of the collection.
This is not good... This way you are retrieving all records and getting a random one. If your table has too many records this could be bad for your app.
G
Gras Double

tl;dr: It's nowadays implemented into Laravel, see "edit 3" below.

Sadly, as of today there are some caveats with the ->orderBy(DB::raw('RAND()')) proposed solution:

It isn't DB-agnostic. e.g. SQLite and PostgreSQL use RANDOM()

Even worse, this solution isn't applicable anymore since this change: $direction = strtolower($direction) == 'asc' ? 'asc' : 'desc';


edit: Now you can use the orderByRaw() method: ->orderByRaw('RAND()'). However this is still not DB-agnostic.

FWIW, CodeIgniter implements a special RANDOM sorting direction, which is replaced with the correct grammar when building query. Also it seems to be fairly easy to implement. Looks like we have a candidate for improving Laravel :)

update: here is the issue about this on GitHub, and my pending pull request.

edit 2: Let's cut the chase. Since Laravel 5.1.18 you can add macros to the query builder:

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

Usage:

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

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


edit 3: Finally! Since Laravel 5.2.33 (changelog, PR #13642) you can use the native method inRandomOrder():

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

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

You should change the 5.1 macro name to inRandomOrder so it's forward compatible ;) details, details :)
That's precisely one thing I did while preparing a 5.1 project before migrating it to 5.2.
This is such a great answer. If I could fav an answer, I would!
s
simhumileco

You can use:

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

T
Teodor Talov

In Laravel 4 and 5 the order_by is replaced by orderBy

So, it should be:

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

User::orderBy(DB::raw('RAND()'))->get();
It works thanks, but could you give some information how this works?
Can you be a little more specific? What kind of information?
T
Talles Airan

it's very simple just check your laravel version

Laravel >= 5.2:

User::inRandomOrder()->get();
//or to get the specific number of records
// 5 indicates the number of records
User::inRandomOrder()->limit(5)->get();
// get one random record
User::inRandomOrder()->first();

or using the random method for collections:

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

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

B
Bilal Gultekin

You can also use order_by method with fluent and eloquent like as:

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

This is a little bit weird usage, but works.

Edit: As @Alex said, this usage is cleaner and also works:

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

this works as well and is a little cleaner.. ->order_by(\DB::raw('RAND()'))
M
Manuel Azar

For Laravel 5.2 >=

use the Eloquent method:

inRandomOrder()

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

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


Course::inRandomOrder()->take(20)->get(); Not working for me - bad sort specification in Find.php line 219
This one's useful for model factories or db seeding
E
Eric Aya

Use Laravel function

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

s
simhumileco

You can easily Use this command:

// Question : name of Model // take 10 rows from DB In shuffle records...

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

g
giovannipds

I prefer to specify first or fail:

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

B
Brad Ahrens

Laravel has a built-in method to shuffle the order of the results.

Here is a quote from the documentation:

shuffle()

The shuffle method randomly shuffles the items in the collection:

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

$shuffled = $collection->shuffle();

$shuffled->all();

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

You can see the documentation here.


N
Neto Braghetto

At your model add this:

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

then at route/controller

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

s
simhumileco

There is also whereRaw('RAND()') which does the same, you can then chain ->get() or ->first() or even go crazy and add ->paginate(int).


D
Doc

I have table with thousands of records, so I need something fast. This is my code for pseudo random row:

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

The problem with this is that if there are multiple rows with ids greater than $count only the first of these would ever be retrieved, and so it would also be more likely to be retrieved than any other row.
佚名

Try this code! It Works:

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

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
h
hackernewbie

Here's how I get random results in eloquent in one of my projects:

$products           =  Product::inRandomOrder()->limit(10);

10 - The number of random records to pull.


C
Cody Gray

In Laravel 7.x and above, you can just do:

$data = Images::all()->random(4);

This should be used with extreme care, because whole data will be fetched from database before being randomly filtered. Avoid this on large table