두 개의 Eloquent 컬렉션을 병합하는 방법은 무엇입니까?


87

질문 테이블과 태그 테이블이 있습니다. 주어진 질문의 태그에서 모든 질문을 가져오고 싶습니다. 예를 들어, 주어진 질문에 "Travel", "Trains"및 "Culture"태그를 붙일 수 있습니다. 이 세 태그에 대한 모든 질문을 가져올 수 있기를 원합니다. 까다로운 점은 질문과 태그 관계가 Eloquent에서 belongsToMany로 정의 된 다 대다라는 것입니다.

다음과 같이 질문 모음을 병합하려고 생각했습니다.

foreach ($question->tags as $tag) {
    if (!isset($related)) {
        $related = $tag->questions;
    } else {
        $related->merge($tag->questions);
    }
}

그래도 작동하지 않는 것 같습니다. 아무것도 병합하지 않는 것 같습니다. 올바르게 시도하고 있습니까? 또한 Eloquent에서 다 대다 관계에서 행의 행을 가져 오는 더 좋은 방법이 있습니까?


eager loading 및 with 메소드에 대한 문서를 확인 했습니까? 더 나은 설득력있는 쿼리를 사용하면 문제를 쉽게 해결할 수 있습니다. 내가 컴퓨터 뒤에 있으면 누군가 나를 때리지 않는 한 예제를 쓸 것입니다.
Luceos

1
@Luceos with는 도움이되지 않습니다. 그건 whereHas아래의 대답처럼 - 그 필요합니다.
Jarek Tkaczyk

네, 내 실수입니다. 당신이 맞습니다
Luceos

답변:


139

merge 메서드는 병합 된 컬렉션을 반환하며 원본 컬렉션을 변경하지 않으므로 다음을 수행해야합니다.

$original = new Collection(['foo']);

$latest = new Collection(['bar']);

$merged = $original->merge($latest); // Contains foo and bar.

코드에 예제 적용

$related = new Collection();

foreach ($question->tags as $tag)
{
    $related = $related->merge($tag->questions);
}

1
푸시를 사용하여 트리에서 플랫 목록을 작성하려고했지만 foreach 접근 방식이 정말 도움이되었습니다.
George

Eloquent 컬렉션은 일반 컬렉션처럼 작동하지 않습니다. 그들은 사용 getKey하므로, 병합 결과Model::all()->merge(Model::all())->count() === Model::all()->count()
eithed

34

merge()메서드 Collection는 호출 된 컬렉션을 수정하지 않습니다. 새 데이터가 병합 된 새 컬렉션을 반환합니다. 다음이 필요합니다.

$related = $related->merge($tag->questions);

그러나 나는 당신이 잘못된 각도에서 문제를 다루고 있다고 생각합니다.

특정 기준을 충족하는 질문을 찾고 있으므로 그런 방식으로 쿼리하는 것이 더 쉬울 것입니다. has()whereHas()방법은 관련 기록의 존재를 기반으로 쿼리를 생성하는 데 사용됩니다.

태그가있는 질문을 찾고 있다면 has()방법을 사용합니다 . 특정 태그가있는 질문을 찾고 있으므로를 사용 whereHas()하여 조건을 추가합니다.

따라서 'Travel', 'Trains'또는 'Culture'중 하나 이상의 태그가있는 모든 질문을 원하는 경우 쿼리는 다음과 같습니다.

$questions = Question::whereHas('tags', function($q) {
    $q->whereIn('name', ['Travel', 'Trains', 'Culture']);
})->get();

이러한 태그 3 개가 모두 포함 된 모든 질문을 원하는 경우 쿼리는 다음과 같습니다.

$questions = Question::whereHas('tags', function($q) {
    $q->where('name', 'Travel');
})->whereHas('tags', function($q) {
    $q->where('name', 'Trains');
})->whereHas('tags', function($q) {
    $q->where('name', 'Culture');
})->get();

1
+, 그러나 제안한 두 번째 (모든 태그) 옵션은 단순화 될 수 있습니다. stackoverflow.com/a/24706347/784588
Jarek Tkaczyk

하지만 태그 이름은 하드 코딩 할 수 없습니다. 이 예에서, 문제는 그 태그가 우연히,하지만 다른 질문에 태그 달라집니다
Allfarid 모랄레스 가르시아


11

두 개의 서로 다른 웅변적인 컬렉션을 하나로 병합하면 일부 개체는 동일한 ID를 가지며 하나는 다른 하나를 덮어 씁니다. 대신 push () 메서드를 사용하거나 문제에 대한 접근 방식을 다시 생각하여 문제를 피하십시오. 웹 참조


감사합니다. 여기 medium.com/@jeffparr_57441/… 에서 찾은 댓글에 덮어 쓰지 않고 깔끔하게 작업을 수행하는 것 같습니다.
Mark

1

모두 웅변 적 컬렉션 에서 저에게 적합하지 않습니다 . laravel 웅변 적 컬렉션 은 병합 문제를 일으키는 것으로 생각 되는 항목의 키를 사용합니다 . 첫 번째 컬렉션을 배열로 다시 가져 와서 새 컬렉션에 넣은 다음 다른 컬렉션을 밀어 넣어야합니다. 새로운 컬렉션;

public function getFixturesAttribute()
{
    $fixtures = collect( $this->homeFixtures->all() );
    $this->awayFixtures->each( function( $fixture ) use ( $fixtures ) {
        $fixtures->push( $fixture );
    });
    return $fixtures;
}

1

각 유창한 컬렉션에 대한 새로운 기본 컬렉션을 만들면 병합이 효과적입니다.

$foo = collect(Foo::all());
$bar = collect(Bar::all());
$merged = $foo->merge($bar);

이 경우 기본 키에 의해 충돌이 발생하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.