简体   繁体   English

Laravel雄辩的极限结果

[英]Laravel eloquent limit results

I have a working query: 我有一个有效的查询:

Object::all()->with(['reviews' => function ($query) {
            $query->where('approved', 1);
        }])

And I want to limit the number of reviews, per object, that is returned. 我想限制返回的每个对象的评论数。 If I use: 如果我使用:

Object::all()->with(['reviews' => function ($query) {
            $query->where('approved', 1)->take(1);
        }])

or 要么

Object::all()->with(['reviews' => function ($query) {
            $query->where('approved', 1)->limit(1);
        }])

it limits the total number of reviews, where I want to limit the reviews that are returned by each object . 它限制了评论的总数, 我想限制每个对象返回的评论 How can I achieve this? 我该如何实现?

Eloquent way 口才

Make one relationship like below in your model class 在模型课程中建立如下所示的一种关系

 public function reviews() {
       return $this->hasMany( 'Reviews' );
    } 

  //you can pass parameters to make limit dynamic
  public function firstReviews() {
        return $this->reviews()->limit( 3 );
    }

Then call 然后打电话

Object::with('firstReviews')->get();

Faster way(if you just need one review) 更快的方式(如果您只需要进行一次审核)

Make a derived table to get the latest review 1st and then join it. 制作派生表以获取最新评论1st,然后加入。

Object->select('*')
      ->leftJoin(DB::raw('(SELECT object_id, reviews  FROM reviews WHERE approved=1 ORDER BY id DESC limit 0,1
        as TMP'), function ($join) {
            $join->on ( 'TMP.object_id', '=', 'object.id' );
        })
      ->get();

Grabbing 1 child per parent 每个父母抓住一个孩子

You can create a helper relation to handle this very easily... 您可以创建一个助手关系来非常轻松地处理此问题。

In your Object model 在您的Object模型中

public function approvedReview()
{
    return $this->hasOne(Review::class)->where('approved', 1);
}

Then you just use that instead of your other relation. 然后,您仅使用它而不是其他关系。

Object::with('approvedReview')->get();


Grabbing n children per parent 每个父母抓住n个孩子

If you need more than 1, things start to become quite a bit more complex. 如果您需要的数量超过1,事情会变得越来越复杂。 I'm adapting the code found at https://softonsofa.com/tweaking-eloquent-relations-how-to-get-n-related-models-per-parent/ for this question and using it in a trait as opposed to a BaseModel . 我正在针对此问题改编https://softonsofa.com/tweaking-eloquent-relations-how-to-get-n-related-models-per-parent/上找到的代码,并将其用于特征而不是一个BaseModel

I created a new folder app/Traits and added a new file to this folder NPerGroup.php 我创建了一个新的文件夹app/Traits并将新文件添加到该文件夹NPerGroup.php

namespace App\Traits;

use DB;

trait NPerGroup
{

    public function scopeNPerGroup($query, $group, $n = 10)
    {
        // queried table
        $table = ($this->getTable());

        // initialize MySQL variables inline
        $query->from( DB::raw("(SELECT @rank:=0, @group:=0) as vars, {$table}") );

        // if no columns already selected, let's select *
        if ( ! $query->getQuery()->columns)
        {
            $query->select("{$table}.*");
        }

        // make sure column aliases are unique
        $groupAlias = 'group_'.md5(time());
        $rankAlias  = 'rank_'.md5(time());

        // apply mysql variables
        $query->addSelect(DB::raw(
            "@rank := IF(@group = {$group}, @rank+1, 1) as {$rankAlias}, @group := {$group} as {$groupAlias}"
        ));

        // make sure first order clause is the group order
        $query->getQuery()->orders = (array) $query->getQuery()->orders;
        array_unshift($query->getQuery()->orders, ['column' => $group, 'direction' => 'asc']);

        // prepare subquery
        $subQuery = $query->toSql();

        // prepare new main base Query\Builder
        $newBase = $this->newQuery()
            ->from(DB::raw("({$subQuery}) as {$table}"))
            ->mergeBindings($query->getQuery())
            ->where($rankAlias, '<=', $n)
            ->getQuery();

        // replace underlying builder to get rid of previous clauses
        $query->setQuery($newBase);
    }
}

In your Object model, import the trait use App\\Traits\\NPerGroup; Object模型中, use App\\Traits\\NPerGroup;导入特征use App\\Traits\\NPerGroup; and don't forget to add use NPerGroup right under your class declaration. 并且不要忘记在类声明下添加use NPerGroup

Now you'd want to setup a relationship function to use the trait. 现在,您想要设置一个关系函数以使用特征。

public function latestReviews()
{
    return $this->hasMany(Review::class)->latest()->nPerGroup('object_id', 3);
}

Now you can use it just like any other relationship and it will load up the 3 latest reviews for each object. 现在,您可以像使用其他任何关系一样使用它,它将为每个对象加载3条最新评论。

Object::with('latestReviews')->get();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM