Laravel - красноречивый или свободный случайный ряд

242

Как я могу выбрать случайную строку, используя Eloquent или Fluent в Laravel Framework?

Я знаю, что с помощью SQL вы можете сделать заказ с помощью RAND (). Тем не менее, я хотел бы получить случайную строку без подсчета количества записей до первоначального запроса.

Любые идеи?

DigitalWM
источник
Нет лучшего способа сделать это, не выполнив хотя бы два запроса.
НАРКОЗ

Ответы:

587

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

Ларавелла 3:

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

Проверьте эту статью на случайных строках MySQL. Laravel 5.2 поддерживает это, для более старой версии нет лучшего решения, чем использование RAW Queries .

edit 1: Как упоминалось в Double Gras, orderBy () не допускает ничего, кроме ASC или DESC, с момента этого изменения. Я обновил свой ответ соответственно.

edit 2: Laravel 5.2 наконец-то реализует функцию-обертку для этого. Это называется inRandomOrder () .

Aebersold
источник
81
Замените «get» на «first», если вы хотите одну строку.
Коллин Прайс
14
для использования с PostgreSQL'RANDOM()'
dwenaus
2
Предупреждение: на больших наборах данных это очень медленно, добавляя около 900 мс для меня
S ..
3
Можем ли мы сделать это?
Ирфанди Д. Венди
3
Вы можете, однако, сортировка будет случайной на каждой новой странице. Что не имеет смысла, потому что это по сути то же самое, что и нажатие клавиши F5.
Aebersold
49

Это работает просто отлично,

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

Вы также можете изменить аргумент в случайной функции, чтобы получить более одной записи.

Примечание: не рекомендуется, если у вас огромные данные, так как сначала будут извлечены все строки, а затем возвращено случайное значение.

Маниш
источник
61
Недостатком в производительности является то, что все записи извлекаются.
Гра Двойной
3
здесь random вызывается для объекта коллекции, а не для запроса sql. случайная функция запускается на стороне php
astroanu
@astroanu Правильно, но для заполнения этой коллекции запрашиваются все строки.
MetalFrog
1
Я могу ошибаться, но это не работает, когда параметр, передаваемый случайной функции, равен размеру коллекции.
Бринн Бейтман
Это не хорошо ... Таким образом, вы извлекаете все записи и получаете случайную. Если в вашей таблице слишком много записей, это может быть плохо для вашего приложения.
Андерсон Сильва
34

tl; dr: В настоящее время он реализован в Laravel, см. «edit 3» ниже.


К сожалению, на сегодняшний день есть несколько предостережений с ->orderBy(DB::raw('RAND()'))предлагаемым решением:

  • Это не DB-агностик. например, использование SQLite и PostgreSQLRANDOM()
  • Хуже того, это решение больше не применимо после этого изменения :

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


Редактирование: Теперь вы можете использовать orderByRaw () метод: ->orderByRaw('RAND()'). Однако это все еще не DB-агностик.

FWIW, CodeIgniter реализует специальное RANDOMнаправление сортировки, которое заменяется правильной грамматикой при построении запроса. Также это кажется довольно простым для реализации. Похоже, у нас есть кандидат на улучшение Laravel :)

обновление: вот проблема об этом на GitHub, и мой ожидающий запрос на извлечение .


редактировать 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 ( changelog , PR # 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.
Двойной Гра
Это такой отличный ответ. Если бы я мог одобрить ответ, я бы!
mwallisch
18

В Laravel 4 и 5order_by заменяетсяorderBy

Итак, должно быть:

User::orderBy(DB::raw('RAND()'))->get();
Теодор Талов
источник
Пользователь :: OrderBy (DB :: сырец ( 'RAND ()')) -> Get ();
Дариус
1
Это работает, спасибо, но не могли бы вы дать некоторую информацию, как это работает?
алайли
Можете ли вы быть немного более конкретным? Что за информация?
Теодор Талов
17

Вы можете использовать :

ModelName::inRandomOrder()->first();
simhumileco
источник
9

Для Laravel 5.2> =

используйте метод Eloquent:

inRandomOrder()

Метод inRandomOrder может использоваться для случайной сортировки результатов запроса. Например, вы можете использовать этот метод для выборки случайного пользователя:

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

из документов: https://laravel.com/docs/5.2/queries#ordering-grouping-limit-and-offset

Мануэль Азар
источник
Курс :: inRandomOrder () -> взять (20) -> Get (); У меня не работает - плохая сортировка в строке Find.php 219
MJ
1
Это полезно для модельных фабрик или посева в дб
Салех Махмуд
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 ()'))
Алекс Наспо
3

Используйте функцию Laravel

ModelName::inRandomOrder()->first();
Камлеш Пол
источник
3

Вы можете легко использовать эту команду:

// Вопрос: имя модели
// взять 10 строк из БД в случайных записях ...

$questions = Question::orderByRaw('RAND()')->take(10)->get();
шланг азими
источник
3

Я предпочитаю указывать в первую очередь или нет:

$collection = YourModelName::inRandomOrder()
  ->firstOrFail();
giovannipds
источник
3

В Laravel есть встроенный метод для изменения порядка результатов.

Вот цитата из документации:

shuffle()

Метод shuffle случайным образом перемешивает элементы в коллекции:

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

$shuffled = $collection->shuffle();

$shuffled->all();

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

Вы можете увидеть документацию здесь .

AlmostPitt
источник
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).

ctf0
источник
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(); 
Кшиштоф Хелховский
источник
Проблема заключается в том, что, если есть несколько строк с идентификаторами, превышающими $countтолько первую из них, они будут извлечены, и поэтому он также будет получен с большей вероятностью, чем любая другая строка.
Кемика