Laravel-雄辩或流利的随机行


241

如何在Laravel框架中使用Eloquent或Fluent选择随机行?

我知道通过使用SQL,您可以通过RAND()进行订购。但是,我想在计算初始查询之前的记录数的情况下获得随机行。

有任何想法吗?


没有执行至少两个查询就没有最好的方法。
NARKOZ

Answers:


583

Laravel> = 5.2:

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

要么

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

或获取特定数量的记录

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

查看有关MySQL随机行的本文。Laravel 5.2支持这一点,对于较旧的版本,没有比使用RAW Queries更好的解决方案了。

编辑1:如Double Gras所述,由于更改,orderBy()不允许ASC或DESC之后的任何其他内容。我相应地更新了我的答案。

编辑2: Laravel 5.2最终为此实现了包装函数。它称为inRandomOrder()


81
如果要单行,请将“ get”替换为“ first”。
Collin Price

14
PostgreSQL使用'RANDOM()'
dwenaus

2
警告:对大数据集,这是非常缓慢的,加上大约900毫秒我
秒。

3
我们可以分页吗?
Irfandi D. Vendy

3
您可以,但是在每个新页面上排序都是随机的。这没有任何意义,因为它与按F5基本上相同。
aebersold

49

这样很好,

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

您还可以在随机函数中更改参数以获取多个记录。

注意:如果您有大量数据,则不建议这样做,因为这将首先获取所有行,然后返回随机值。


61
从性能角度来看,缺点是要检索所有记录。
Gras Double

3
在这里,对集合对象而不是sql查询调用random。随机函数在php端运行
astroanu 2015年

@astroanu是的,但是要填充该集合,将查询所有行。
MetalFrog

1
我可能是错的,但是当传递给随机函数的参数与集合的大小相同时,这似乎不起作用。
Brynn Bateman

这不好。...这样您将检索所有记录并获得一个随机记录。如果表中的记录太多,则可能对您的应用不利。
Anderson Silva

34

tl; dr:如今已在Laravel中实现,请参见下面的“ edit 3”。


遗憾的是,截止到今天,->orderBy(DB::raw('RAND()'))提出的解决方案有一些警告:

  • 它与数据库无关。例如SQLite和PostgreSQL使用RANDOM()
  • 更糟糕的是,由于此更改,此解决方案不再适用:

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


编辑:现在您可以使用orderByRaw()方法:->orderByRaw('RAND()')。但是,这仍然不是DB不可知的。

FWIW,CodeIgniter实现了一个特殊的 RANDOM排序方向,在构建查询时将其替换为正确的语法。而且它似乎很容易实现。看来我们有一个候选人可以改善Laravel :)

更新:这是关于GitHub 的问题,以及我的待处理的pull request


编辑2:让我们切入正题。从Laravel 5.1.18开始,您可以将宏添加到查询构建器中:

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

用法:

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

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


编辑3:最后!从Laravel 5.2.33(changelogPR#13642)开始,您可以使用本机方法inRandomOrder()

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

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

您应该将5.1宏名称更改为inRandomOrder,以便它是向前兼容的;)详细信息,详细信息:)
Sander Visser

这正是我在准备5.1项目并将其迁移到5.2时所做的一件事。
Gras Double

这是一个很好的答案。如果我能回答这个问题,我会的!
mwallisch



9

对于Laravel 5.2> =

使用口才方法:

inRandomOrder()

inRandomOrder方法可用于对查询结果进行随机排序。例如,您可以使用此方法来获取随机用户:

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

来自文档:https : //laravel.com/docs/5.2/queries#ordering-grouping-limit-and-offset


课程:: inRandomOrder()-> take(20)-> get(); 不是为我工作-坏人规范在Find.php线219
MJ

1
这对于模型工厂或数据库播种很有用
Saleh Mahmood

8

您还可以流畅,雄辩地使用order_by方法,例如:

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

这有点奇怪,但是可以用。

编辑:正如@Alex所说,这种用法更清洁,也可以工作:

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

3
-> order_by(\ DB :: raw('RAND()'))
Alex Naspo


3

您可以轻松使用以下命令:

//问题:模型名称
//从数据库中抽取10行在随机记录中...

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

3

我更喜欢先指定还是失败:

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

3

Laravel有一个内置的方法来随机排列结果的顺序。

这是文档中的报价:

shuffle()

随机播放方法随机随机播放集合中的项目:

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

$shuffled = $collection->shuffle();

$shuffled->all();

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

您可以在此处查看文档


2

在您的模型上添加以下内容:

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

然后在路线/控制器处

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

2

还有whereRaw('RAND()')哪些不一样的,你就可以链->get()或者->first()甚至发疯,并添加->paginate(int)


0

我的桌子上有成千上万条记录,所以我需要快速一些。这是我的伪随机行代码:

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

这样做的问题是,如果有多个ID大于$count仅其中第一个ID的行将被检索到,那么与其他任何行相比,也更有可能被检索到。
kemika'9
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.