Laravel - 随机分页记录

11

我们如何在 Laravel 中对随机记录进行分页显示?例如:

$products = Product::all()->orderBy(DB::raw('RAND()'));
$products->paginate(4);
$products->setPath('products');
上述操作会导致重复记录,因为顺序是随机的。 我该如何持久化 $products 对象,以便在新的页面请求时,它可以通过相同/固定的随机记录集进行过滤?

1
请告诉我们您已经尝试过什么,以及什么没有起作用。 - Alexandre Cartapanis
1
@AlexandreCartapanis - 分页功能会出现重复记录。我们使用了上述代码。 - dang
3个回答

25

当你深入阅读mysql的文档 并查找RAND()功能时,你会发现可以使用“种子”。

通过使用种子,您将始终获得随机化的相同结果。

示例:

$products = Product

    ::all()

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

    ->paginate(4);
你可以生成自己的种子并将其存储在会话或其他地方以记住它。 更新 Laravel查询构建器现在有一个完全相同的功能:
$products = Product

    ::all()

    ->inRandomOrder('1234')

    ->paginate(4);

+1. 由于我没有使用Eloquent,我很幸运地发现,显然集合“shuffle”辅助函数允许“seed”参数,如果您正在使用分页并希望在后续页面上防止重复,则这非常有用:https://github.com/illuminate/support/blob/5.6/Collection.php#L1380 - Ryan

1

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

使用DB::raw()和我们上面设置的会话变量,将orderBy()添加到Eloquent查询中:

->orderBy(DB::raw('RAND('.$request->session()->get('session_rand').')'))

1

解决方案 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

前端Ajax调用:当页面滚动到页面底部时,变量“page”将自动增加并请求后端获取更多产品。如果返回更多产品,则将这些产品附加到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
        });
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接