2017-01-18 2 views
1

사진을 나타내는 앨범 모델과 AlbumItem 모델이 있습니다. 앨범 모델에서Eloquent hasOne by group by

내가 가진 : 컨트롤러에서

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

은 내가 먼저 사진으로 앨범을 목록을로드는 :

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

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

그것은이 같은 SQL 쿼리를 생성

하지만 album_id = 1,2,3 인 모든 앨범 항목을 반환합니다. 4,5 ...
그리고 가장 작은 값이 sort_order 인 첫 번째 앨범 항목 만 필요하므로 GROUP BY를 사용하려고했지만 ORDER BY가 작동하지 않습니다 ... 즉 first_photo() 메서드를 변경하려고합니다. sort_order BY 첫 번째 순서, 다음 album_id BY GROUP :

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 방법이 얻을 수 있습니까?

+0

..'$ this-을 반환> hasOne의 ('AlbumItem') -> 해 orderBy ('SORT_ORDER', '오름차순'는);'-,하지 마십시오 [범위] (https를 사용 : //laravel.com/docs/5.3/eloquent#query-scopes) 대신 *.하지만 album_id = 1,2,3,4,5 * 인 모든 앨범 항목을 반환합니다. 예, 그렇습니다. (그리고 'AlbumItem'은 관련된'앨범들 '에 매핑 될 것입니다.) ..에 관한, 그리고 가장 작은 값을 가진 첫 번째 앨범 항목 만 필요합니다. - 열정적 인 로딩 제약 조건 (https : // laravel.com/docs/5.3/eloquent-relationships#constraining-eager-loads). –

답변

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

. 그리고 관계와 열의 부하를 정의하면 항상 두 개의 쿼리가 실행됩니다. 여기에 앨범 _id별로 그룹을 추가 할 수도 있습니다. 스타터

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

'-> 'first_photo()'메소드에서'limit (1)'을 실행하고'select * from album_items where sort_order asc limit 1 '의 album_items.album_id를 사용하여 쿼리를 생성했습니다. 한계가 도움이되지 않습니다. 그룹별로 문제를 해결할 수 있지만 그룹화하기 전에 결과를 정렬해야합니다. – 4unkur

+1

앨범 :: with ([ 'first_photo'=> function ($ q) { return $ q-> limit (1) -> groupBy ('앨범 _ id'); }])> get(); 이 시도. –

+0

감사합니다. 대답으로 게시 할 수 있습니다. 동의하겠습니다. – 4unkur

1

글쎄, 난 당신이 아닌 관계 꼬추 (sort, order, group, where 등)과의 관계의 혼란을 피해야한다, 선발을 위해

.. 답을 쓰기로했다.

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

이 뒤에 이론적 근거는 당신이 $model->first_photo()->create([.. relation definition ..])처럼 뭔가를 할 수 있다는 것입니다, 또는 당신은 $albumItem->Album()->associate([$model])을 수, 심지어는 노골적으로 Albumfirst_photo 관계에 AlbumItem 인스턴스를 할당합니다 : 그것은 같은 것으로 변경합니다. 당신이 하고자 그리고 내가를 사용하려고 이유 SORT_ORDER의 가장 작은 값을 갖는 경우에만 첫 번째 앨범 항목을해야하는 경우

, 당신이 시도 할 수 있습니다 :

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

편집 :

그냥 Laravel이 with() 쿼리를 어떻게 처리하는지에 대한 약간의 설명. Laravel은 먼저 Album을 가져오고 Album과 관련된 모든 AlbumItem을 가져 오는 작업을 진행합니다. 매핑은 조인없이 이루어 지지만 PHP에 의해 메모리에서 완료됩니다. 이것은 documentation의 (메모리 부분에 대해서는 명확하지 않습니다.) 명시되어 있습니다. 그러나 Laravel의 Eloquent Query Builder에서는 PHP에서 관계 성냥을 확실히 수행합니다. here$relation->match(..) here을 찾을 수 있습니다. 음, 추상화 된 것 중 하나는 this입니다. 꽤 깊지 만 프레임 워크의 일부를 파야합니다.

이 루프는 테이블의 모든 책을 검색하기 위해 1 개의 쿼리를 실행 한 다음 각 책을 검색하여 저자를 검색합니다. 따라서 25 권의 책이있는 경우이 루프는 26 개의 검색어를 실행합니다. 원래 도서는 1 개, 각 도서의 저자를 검색하려면 25 개의 검색어가 추가로 필요합니다.

감사하게도이 작업을 2 개의 쿼리로 줄이기 위해 eager 로딩을 사용할 수 있습니다.쿼리 할 때 관계 방법으로를 사용하여로드 열망해야하는 지정할 수 있습니다 : 이것은 단지 하나의 값을 반환합니다

+0

이 코드는 다음과 같이 생성합니다 :'select * from album_items sort_order asc limit 1에 의해 (?,?,?) order에있는 album_items.album_id where 각 앨범에 대해 단지 1 행을 반환하지만 1 행을 반환하지 않습니다. – 4unkur

+0

@ 4unkur '-> with()'쿼리를 사용하여 Laravel은 두 개의 쿼리를 실행합니다. 하나는'Album'을 가져 오기위한 것이고, 두번째 것은 관련된'AlbumItem'을 가져 오는 것입니다 - 모두 join없이 끝납니다. 매핑은 코드에서 처리 될 것입니다. [참고] (https://github.com/laravel/framework/blob/5.3/src/Illuminate/Database/Eloquent/Builder.php#L691) –