Eloquent在分组之前有一个订单

时间:2017-01-18 08:17:32

标签: laravel laravel-4

我有Album模型和AlbumItem模型 - 它代表照片。

在相册模型中,我有:

public function first_photo(){
   return $this->hasOne('AlbumItem')->orderBy('sort_order', 'asc');
}

在控制器中,我使用第一张照片加载了相册列表:

Album::with(['first_photo'])->get();

它生成如下的SQL查询:

select * from `album_items` 
where `album_items`.`album_id` in (1,2,3,4,5) order by `sort_order` asc

但它会返回所有具有album_id = 1,2,3,4,5 ...
的专辑项目 我只需要第一个具有sort_order最小值的专辑项目,这就是为什么我尝试使用GROUP BY但是然后ORDER BY不起作用...即我想要更改first_photo()方法所以它会首先是ORDER BY sort_order,然后是GROUP BY album_id

select * from (
  select * from `album_items` 
  where `album_items`.`album_id` in (1,2,3,4,5) order by `sort_order` asc
) temp
group by temp.`album_id`

是否可以使用hasOne方法获取此内容?

2 个答案:

答案 0 :(得分:3)

public function first_photo(){
   return $this->hasOne('AlbumItem')->orderBy('sort_order', 'asc')->limit(1);
}

这将只返回一个值。当我们定义关系和急切负载时,它将始终触发两个查询。您也可以在此处按album_id添加分组。

Album::with(['first_photo'=> function($q){ 
   return $q->limit(1)->groupBy('album_id');
}])->get(); 

答案 1 :(得分:1)

好吧,我决定写一个答案..

对于初学者,你应该避免与非关系事物(sortordergroupwhere等)的混乱。将其更改为:

public function first_photo(){
   return $this->hasOne('AlbumItem');
}

这背后的理由是您可以执行类似$model->first_photo()->create([.. relation definition ..])的操作,或者$albumItem->Album()->associate([$model]),或者甚至可以明确地将AlbumItem实例分配给Album&#39} first_photo关系。

如果您希望我只需要第一个具有最小sort_order值的相册项目,这就是我尝试使用的原因,您可以尝试:

Album::with(['first_photo' => function($query){
                                                $query->orderBy('sort_order', 'asc')->first();
                                              }])->get();

修改

关于Laravel如何处理with()查询的一些解释。 Laravel将首先获取指定的Album,然后继续获取与AlbumItem相关的所有Album。映射是在没有连接的情况下完成的,但是由PHP在内存中完成。 documentation中陈述了这一点(内存部分并不十分清楚)。但是,在Laravel的Eloquent Query Builder深处,他们肯定会在PHP中进行关系匹配 - 可以找到here$relation->match(..) here,好吧,它是一个摘要,其中一个例子是this。相当深,但你应该挖掘框架的一部分..

  

此循环将执行1个查询以检索表中的所有书籍,然后执行另一个查询以检索作者。因此,如果我们有25本书,这个循环将运行26个查询:1个用于原始书籍,25个额外查询用于检索每本书的作者。

     

幸运的是,我们可以使用预先加载将此操作减少到只有2个查询。查询时,您可以使用with方法指定应该急切加载哪些关系: