Laravel - Пагінація випадкових записів

Як ми можемо розбивати на сторінки випадкові записи в laravel? наприклад:

$products = Product::all()->orderBy(DB::raw('RAND()'));
$products->paginate(4);
$products->setPath('products');

Вищезазначене закінчується повторюваними записами через випадковий порядок. Як я можу зберегти об’єкт $products, щоб, коли надсилається запит на нову сторінку, він мав фільтрувати той самий/фіксований набір випадкових записів?


person dang    schedule 31.05.2016    source джерело
comment
Розкажіть, будь ласка, що ви вже пробували, а що не працює   -  person Alexandre Cartapanis    schedule 31.05.2016
comment
@AlexandreCartapanis - розбиття на сторінки дає повторювані записи. Ми використали наведений вище код.   -  person dang    schedule 31.05.2016


Відповіді (3)


Коли ви зануритесь у документаціюmysql і знайдіть функцію RAND(), і ви побачите, що ви можете використовувати "початкове число".

Використовуючи вихідний код, ви завжди отримуватимете однакові рандомізовані результати.

приклад:

$products = Product

    ::all()

    ->orderBy(DB::raw('RAND(1234)'))

    ->paginate(4);

Ви можете створити своє власне насіння та зберегти його в сеансі або щось, щоб запам’ятати його.

Оновити

Конструктор запитів Laravel тепер має функцію, яка точно так само:

$products = Product

    ::all()

    ->inRandomOrder('1234')

    ->paginate(4);
person Thomas Van der Veen    schedule 31.05.2016
comment
+1. Оскільки я не користуюся Eloquent, мені пощастило виявити, що допоміжна функція Collection shuffle також дозволяє початковий параметр, який корисний, якщо ви використовуєте розбивку на сторінки та хочете запобігти повторенню на наступних сторінки: github.com/illuminate/support/blob/5.6/Collection. php#L1380 - person Ryan; 24.06.2018

Рішення з Laravel + Eloquent

Перед запитом Eloquent встановіть змінну сеансу. Я використовував time() для значення сеансу, тому я можу зберегти той самий порядок протягом певного часу. Наприклад, 3600 секунд (1 година).

if ($request->session()->has('session_rand')) {

    if((time() - $request->session()->get('session_rand')) > 3600){
        $request->session()->put('session_rand', time());
    }
}else{
    $request->session()->put('session_rand', time());
}

Додайте ->orderBy() до запиту Eloquent за допомогою DB::raw() і змінної сеансу, яку ми встановили вище:

->orderBy(DB::raw('RAND('.$request->session()->get('session_rand').')'))
person Darren Murphy    schedule 14.09.2018

Рішення Ajax + chunk + session + lazyload + paginate + eloquent + blade

отримати всі продукти, встановити кількість елементів для кожного блоку (наприклад, розбити на сторінки) і зберегти його в сесії (ми зберігаємо фрагменти в сеансі, щоб, коли надходить запит ajax, він не викликав $products = Product::inRandomOrder()->get(); знову), перший фрагмент буде першим розбиттям на сторінки

коли ajax запитує більше продуктів, він отримає продукти із сеансу та отримає правильну частину бази продуктів на номері сторінки, яку запитує ajax.

якщо шматків більше немає, просто поверніться без продуктів

    if(!$request->ajax()){

        $products = Product::inRandomOrder()->get();
        $chunks = $products->chunk(4);

        \Session::put('chunks',$chunks);
        $products = $chunks[0];
    }else{
        $page = $request->all()['page'];                
        $chunks = \Session::get('chunks');

        if(count($chunks)<$page){
            \Session::forget('chunks');
            return;
        }else{
            $products = $chunks[$page-1];
        }
    }

   if ($request->ajax()) {
        $view =  view('product_lazyLoad',compact('products'))->render();
        return response()->json(['html'=>$view]);
   }

   return view('products',compact('products'));

products.blade.php : головна сторінка

@if($products)
    <ul class="row" id="productLists">
        @include('product_lazyLoad')
    </ul>
@endif

<!-- load records -->

<div class="col-12 ajax-load text-center" style="display:none">
    <p><img src="/images/loader.gif">Loading More Products</p>
</div>

product_lazyload.blade.php : відображення продуктів

@foreach($products as $product)
    <div>
        <p>Display your products here</p>
    </div>
@endforeach

font-end ajax виклик: коли сторінка прокручується донизу сторінки, змінна сторінка автоматично збільшуватиметься та запитуватиме бекенд для інших продуктів. якщо буде повернуто більше продуктів, вони будуть додані до елемента з id = "productlist" у products.blade.php

    //lazy load
    var page = 1;
    $(window).scroll(function() {
        if($(window).scrollTop() + $(window).height() >= $(document).height()) 
        {
            page++;
            loadMoreData(page);
        }
    });

  function loadMoreData(page){
        $.ajax({
            url: '?page=' + page,
            type: "get",
            beforeSend: function(){
                $('.ajax-load').show();
            }
        }).done(function(data){
            if(!data.html){
                $('.ajax-load').html("No more records found");
                $('.ajax-load').show();
                return;
            }

            $('.ajax-load').hide();
            $("#productLists").append(data.html);

        }).fail(function(jqXHR, ajaxOptions, thrownError){
             //error handle
        });
    }
person Jason    schedule 17.12.2018