按关系栏排序

问题描述 投票:0回答:9

我有以下疑问:

$items = UserItems::with('item')
        ->where('user_id','=',$this->id)
        ->where('quantity','>',0)
        ->get();

我需要按 item.type 订购,所以我尝试了:

$items = UserItems::with('item')
        ->where('user_id','=',$this->id)
        ->where('quantity','>',0)
        ->orderBy('item.type')
        ->get();

但我明白

Unknown column 'item.type' in 'order clause'

我缺少什么?

laravel eloquent
9个回答
74
投票
由于

@rypskar

 评论,
join() 工作得很好

$items = UserItems
        ::where('user_id','=',$this->id)
        ->where('quantity','>',0)
        ->join('items', 'items.id', '=', 'user_items.item_id')
        ->orderBy('items.type')
        ->select('user_items.*') //see PS:
        ->get();

PS:为了避免

id
属性(或两个表之间的任何共享名称属性)重叠并导致错误的值,您应该使用
select('user_items.*')
指定选择限制。


52
投票

您可以使用 withAggregate('relationship', 'column') 函数。

它为 UserItems 实例创建一个“item_type”属性,然后您可以使用 orderBy('item_type') 来定位该属性。
它也可以与 pagination 一起使用,如 limit()、skip() 等,因为它在数据库调用后不使用 sortBy()。

UserItems::withAggregate('item','type')
    ->where('user_id','=',$this->id)
    ->where('quantity','>',0)
    ->orderBy('item_type')
    ->get();

这样,您仍然可以在雄辩的查询中使用关系并对集合进行排序,而无需进行联接或 orderByRaw() 调用。

生成的查询将类似于:

select `users`.*, (select type from `items` where `items`.`user_id` = `users`.`id` limit 1) as `item_type` from `users` where `users`.`id` = 123 AND `users`.`quantity` > 0 order by item_type asc)

21
投票

嗯,您的急切加载可能没有构建您期望的查询,您可以通过启用查询日志来检查它。

但我可能只使用集合过滤器:

$items = UserItems::where('user_id','=',$this->id)
        ->where('quantity','>',0)
        ->get()
        ->sortBy(function($useritem, $key) {
          return $useritem->item->type;
        });

6
投票

我知道这是一个老问题,但你仍然可以使用 没有连接的“orderByRaw”。

$items = UserItems
        ::where('user_id','=',$this->id)
        ->where('quantity','>',0)
        ->orderByRaw('(SELECT type FROM items WHERE items.id = user_items.item_id)')
        ->get();  

2
投票

对于一对多关系,有一种更简单的方法。假设一个订单有很多付款,我们希望按最新付款日期对订单进行排序。 Payments 表有一个名为 order_id 的字段,它是 FK。

我们可以像下面这样写

$orders = Order->orderByDesc(Payment::select('payments.date')->whereColumn('payments.order_id', 'orders.id')->latest()->take(1))->get()

此代码的 SQL 等效项:

select * from orders order by (
    select date
    from payments
    where order_id = payments.id
    order by date desc
    limit 1
) desc

您可以根据您的示例进行调整。如果我理解正确的话,在您的情况下,订单的等价物是用户,付款的等价物是项目。

进一步阅读

https://reinink.ca/articles/ordering-database-queries-by-relationship-columns-in-laravel


2
投票

你可以简单地做到这一点

UserItems::with('item')
  ->where('user_id','=',$this->id)
  ->where('quantity','>',0)
  ->orderBy(
      Item::select('type') 
      ->whereColumn('items.useritem_id','useritems.id')
      ->take(1),'desc'
    )    
  ->get();

1
投票
$items = UserItems::with('item')
        ->where('user_id','=',$this->id)
        ->where('quantity','>',0)
        ->with(['item' => function($q) {
          $q->orderBy('type', 'asc');
        ]})
        ->get();

将关系数组传递给“with”方法,其中:

  • 数组键是关系名称,在本例中是“item”
  • 数组值是一个闭包,为急切加载查询添加额外的约束

0
投票

我找到了另一种使用相关模型中的字段对数据集进行排序的方法,您可以在模型中获取一个函数,该函数获取与相关表的唯一关系(例如:房间与房间类别相关,房间与按类别 id 划分的类别,您可以使用像“room_category”这样的函数,它根据房间模型的类别 id 返回相关类别),之后的代码如下:

Room::with('room_category')->all()->sortBy('room_category.name',SORT_REGULAR,false);

这将为您提供按类别名称排序的房间

我在一个项目中执行了此操作,其中我有一个带有服务器端处理的数据表,并且我遇到了需要按相关实体的字段进行排序的情况,我这样做了并且它有效。更简单,更符合 MVC 标准。

在你的情况下,它会以类似的方式:

User::with('item')->where('quantity','>',0)->get()->sortBy('item.type',SORT_REGULAR,false);

0
投票
$users
->whereRole($role)       
->join('address', 'users.id', '=', 'address.user_id')  
->orderByRaw("address.email $sortType")    
->select('users.*')
© www.soinside.com 2019 - 2024. All rights reserved.