Laravel Eloquent 按关系表列排序
Posted
技术标签:
【中文标题】Laravel Eloquent 按关系表列排序【英文标题】:Laravel Eloquent sort by relation table column 【发布时间】:2014-06-25 03:41:08 【问题描述】:我尝试通过pinned
列从shop_products_options
表中对shop_products
表中的产品进行排序:
$products = Shop\Product::with(['options' => function ($query)
$query->orderBy('pinned', 'desc');
])->paginate(5);
我在 Shop\Product 模型中设置了关系:
public function options()
return $this->hasOne('Shop\Options');
但产品没有排序。我得到一个只适用于shop_products_options
表的查询。
SELECT * FROM `shop_products_options` WHERE `shop_products_options`.`product_id` in ('8', '9', '10', '11', '12') ORDER BY `pinned` DESC
如何解决?
【问题讨论】:
【参考方案1】:急切加载使用单独的查询,因此您需要为此加入:
$products = Shop\Product::join('shop_products_options as po', 'po.product_id', '=', 'products.id')
->orderBy('po.pinned', 'desc')
->select('products.*') // just to avoid fetching anything from joined table
->with('options') // if you need options data anyway
->paginate(5);
SELECT
子句的存在是为了不将连接列附加到您的 Product
模型中。
编辑:根据@alexw 评论 - 如果需要,您仍然可以包含连接表中的列。您可以将它们添加到select
或致电addSelect/selectRaw
等。
【讨论】:
完美 - 此外,如果没有选择,shop_products_options.id
将覆盖 products.id
的值
@Gravy 没错,连接的表字段将覆盖主表中具有相同名称的所有字段。
感谢 Jarek,您帮助我解决了我遇到的类似问题,我需要按相关的 Broadcasts
对象(可能是 Youtube 或 Vimeo 视频)对 Broadcasts
进行排序我想按照他们获得的点赞数对他们进行排序。
另外值得注意的是,如果您有一个更复杂的查询,您可以使用addSelect
而不是select
,并且您确实想要获取来自其他表的列.
@alexw 当然,这是真的。然而问题是关于按关系排序,所以这里更相关的是如何避免意外行为,即包括(并且可能重叠)连接表中的列。【参考方案2】:
如果没有手动加入相关表,您将无法按相关表列排序。 Jarek 的回答是正确的,但这可能真的很尴尬:
1.第一个问题是你需要担心select。
->select('products.*')
原因:可以从 shop_products_options 中选择没有 select() id 并将其水合到 Product 模型中。
2.第二个问题是你需要担心groupBy。
->groupBy('products .id');
原因:如果关系是 HasOne 并且产品有多个 shop_products_options,则查询将返回更多产品行。
3.第三个问题是你需要改变所有其他的where子句:
->where('date', $date)
到
->where('products .date', $date)
原因:products 和 shop_products_options 都可以有 "date" 属性,在这种情况下,如果没有选择带有表 "ambiguous column" 的属性,则会抛出错误。
4.第四个问题是你使用的是表名(不是模型),这也很糟糕和尴尬。
->where('products.date', $date)
5.第五个问题是您需要担心连接表的软删除。如果 shop_products_options 使用 SoftDeletes 特征,您必须添加:
->where('shop_products_options .deleted_at', '=', null)
以上所有问题都非常令人沮丧,使用 eloquent 连接表格会给您的代码带来很多问题。我创建了一个包来解决上述所有问题,你可以用优雅的方式按关系属性排序,对于你的情况,它是:
$products = Shop\Product::orderByJoin('options.pinned', 'desc')->paginate(5);
欲了解更多信息,请参阅https://github.com/fico7489/laravel-eloquent-join
【讨论】:
【参考方案3】:Subquery Ordering+6 Laravel 版本还有另一种方式:
$products = Shop\Product::orderByDesc(
Shop\Options::select('pinned')
->whereColumn('product_id', 'shop_products.id')
->orderByDesc('pinned')
->limit(1)
)->paginate(5);
【讨论】:
哇!哇!谢谢@Ramy,你拯救了我的一周。我花了很多天才找到这个解决方案。再次感谢您的分享! 很高兴它有帮助!以上是关于Laravel Eloquent 按关系表列排序的主要内容,如果未能解决你的问题,请参考以下文章
Laravel Eloquent 模型按局部列和关系模型列值排序
如何对 Eloquent 关系中的数据透视表列进行 GROUP 和 SUM?