如何在laravel中检索有限数量的相关模型并按相关模型对集合进行排序?
Posted
技术标签:
【中文标题】如何在laravel中检索有限数量的相关模型并按相关模型对集合进行排序?【英文标题】:how to retrieve limited number of related model and sort collection by related model in laravel? 【发布时间】:2020-07-19 12:21:50 【问题描述】:我有 3 个模型 店铺模型、产品模型、图片模型
我想检索包含最近 3 个产品型号及其图片的商店集合,并根据最新产品对我的集合进行排序。
我在 laravel 6 中尝试了 leftjoint
和 joint
以便能够对结果进行排序,但我得到了所有商店的产品(我只需要每个商店的最后 3 个产品),
当我使用关节时,我无法检索产品图片
我也在 laravel 中尝试过“with
”方法,我无法根据product.creatred
_at 对结果进行排序,而且我也用这种方法获得了所有相关产品。(正如我提到的,我需要最后 3 个产品)
class Shop extends Model
public function products()
return $this->hasMany('App\Product');
class Product extends Model
public function shop()
return $this->belongsTo('App\Shop');
public function pictures()
return $this->morphMany('App\hPicture', 'pictureable');
Shop::select('shops.*', 'products.id', 'products.shop_id', 'products.name as pname', 'products.user_id', 'products.code', 'products.price')
->with(['pictures', 'products.pictures'])
->leftjoin('products', function ($leftJoin)
$leftJoin->on('shops.id', '=', 'products.shop_id');
);
$dataList = $dataList->orderBy($field, $order);
$dataList = $dataList->paginate(5)->appends(['sortField' => $field, 'sortOrder' => $order]);
产品和店铺模型的表格布局为:
Schema::create('shops', function (Blueprint $table)
$table->increments('id');
$table->string('name');
$table->string('slug');
$table->string('phone')->nullable();
$table->string('address')->nullable();
$table->timestamps();
$table->string('description')->nullable();
$table->uuid('uuid');
);
Schema::create('products', function (Blueprint $table)
$table->increments('id');
$table->integer('shop_id')->unsigned();
$table->foreign('shop_id')->references('id')->on('shops');
$table->string('name');
$table->string('code');
$table->string('slug');
$table->integer('price');
$table->uuid('uuid');
$table->timestamps();
);
【问题讨论】:
【参考方案1】:只有两种方法可以解决这个问题:
-
要么你把所有产品都拉进去,然后最后修剪它们(仅当每家商店的产品不多时才建议这样做):
$shops = Shop::with(['products' => function($subQuery)
$subQuery
->with('pictures') //Running in scope of product, also load each product's pictures
->orderBy('created_at', 'desc');
])
->get();
foreach ($shops as $shop)
$shop->setRelation('products', $shop->products->take(3));
注意:
您将加载链接到您加载的商店的每一个产品。你可能会遇到内存问题。
-
只取你需要的,但引入一个 n+1 查询问题(建议只使用少量
$shops
:
$shops = Shop::get();
foreach ($shops as $shop)
$shop->load([
'products' => function($query)
$query
->orderBy('created_at', 'desc')
->limit(3)
->get();
]);
注意:
N+1 查询问题:您正在为每个商店执行一个新查询,因此如果您有 100 万个商店,就会有 100 万个额外查询。
编辑:(回答评论问题)
问:如何根据 $shops 的最新产品 created_at 字段对它们进行排序?
$sortedShops = $shops->sortBy(function ($shop, $key)
return $shop->products->first()->created_at;
)->values()->all();
sortBy
在集合上被调用(不是 uery)。它允许您遍历每个元素(在本例中为商店)并使用每个对象。请注意,如果您没有与商店关联的产品,此功能将失效。
末尾的->values()->all()
确保当您将商店转换为 json 时,您将创建一个数组,而不是 js 中的对象。
来源: https://laravel.com/docs/7.x/collections#method-sortby
编辑:(删除原来的答案,因为它不起作用)
上一个答案不起作用,因为limit(3)
将限制加载的产品总数,而不是每个商店 3 个产品(我的错)。
【讨论】:
如果它有效,请不要忘记接受答案;)如果无效,请告诉我 事实上,我认为我需要每个商店的最后一个相关产品的最新 created_at 字段才能根据该数据进行排序 取决于您的表格布局。您能发布哪些列在哪些表格中吗?然后我可以试着和你一起找出更好的答案:) 我编辑问题。我希望 $shops 按其最新产品 created_at 归档 @Mostafa,我更新了答案,让我知道它是否有效:)以上是关于如何在laravel中检索有限数量的相关模型并按相关模型对集合进行排序?的主要内容,如果未能解决你的问题,请参考以下文章
列表模型如何按 DOWN-VOTES 的数量排序到相关模型 - laravel,雄辩
Laravel Eloquent - 从相关模型中检索特定列