Laravel - красномовний або вільний випадковий рядок


242

Як я можу вибрати випадковий рядок за допомогою Eloquent або Fluent in Laravel?

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

Будь-які ідеї?


Немає кращого способу зробити це без виконання принаймні двох запитів.
НАРКОЗ

Відповіді:


586

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 .

редагувати 1: Як згадував Double Gras, orderBy () не дозволяє нічого більше, ніж ASC або DESC після цієї зміни. Я відповідно оновив свою відповідь.

редагувати 2: Laravel 5.2 нарешті реалізує для цього функцію обгортки . Це називається inRandomOrder () .


81
Замініть "get" на "first", якщо вам потрібно один рядок.
Коллін Ціна

14
для використання PostgreSQL'RANDOM()'
dwenaus

2
Попередження: для великих наборів даних це дуже повільно, додавши для мене близько 900 мс
S ..

3
Чи можемо ми про це пагінітувати?
Ірфанді Д. Венді

3
Ви можете, однак сортування буде випадковим на кожній новій сторінці. Що не має сенсу, оскільки він по суті такий же, як і ви натискаєте F5.
aebersold

49

Це працює чудово,

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

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

Примітка: не рекомендується, якщо у вас є величезні дані, оскільки це спочатку отримає всі рядки, а потім поверне випадкове значення.


61
Недоліком продуктивності є те, що всі записи отримані.
Гра "Двомісний"

3
тут випадковий виклик об’єкта колекції не запиту sql. випадкова функція виконується на стороні php
astroanu

@astroanu Право, але для заповнення цієї колекції всі рядки запитуються.
MetalFrog

1
Я можу помилитися, але це, здається, не працює, коли параметр, переданий випадковій функції, такий же, як і розмір колекції.
Брін Бейтман

Це не добре ... Таким чином ви отримуєте всі записи та отримуєте випадковий. Якщо у вашій таблиці занадто багато записів, це може бути погано для вашої програми.
Андерсон Сільва

34

tl; dr: Це зараз реалізовано в Laravel, див. "редагувати 3" нижче.


На жаль, на сьогодні існує кілька застережень із ->orderBy(DB::raw('RAND()'))запропонованим рішенням:

  • Це не БД-агностик. наприклад, використання SQLite та PostgreSQLRANDOM()
  • Ще гірше, що це рішення більше не застосовується з моменту цієї зміни :

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


редагувати: Тепер ви можете використовувати метод orderByRaw () :->orderByRaw('RAND()') . Однак це все ще не БД-агностик.

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 (журнал змін , 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

У Ларавелі 4 і 5order_by замінюєтьсяorderBy

Отже, це повинно бути:

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

Користувач :: orderBy (DB :: raw ('RAND ()')) -> get ();
Дарій

1
Це працює спасибі, але ви могли б дати трохи інформації, як це працює?
алайлі

Ви можете бути трохи більш конкретним? Яка інформація?
Теодор Талов


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 () -> взяти (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 ()'))
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(); 

Проблема в цьому полягає в тому, що якщо існує кілька рядків з ідентифікаторами, більшими, ніж $countтільки перший з них, коли-небудь буде вилучено, і тому це також буде більш ймовірним, ніж будь-який інший рядок.
kemika
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.