Як об’єднати дві красномовні колекції?


86

У мене є таблиця запитань і таблиця тегів. Я хочу отримати всі питання з тегів даного питання. Так, наприклад, у мене до даного питання можуть бути прикріплені теги "Подорожі", "Потяги" та "Культура". Я хочу мати можливість отримати всі запитання щодо цих трьох тегів. Складне, так що, здається, полягає у тому, що взаємозв’язок між питаннями та тегами - це багато-до-багатьох, визначене в Eloquent як належать ToMany.

Я думав про спробу об’єднати колекції питань, як показано нижче:

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

Здається, це не працює. Здається, нічого не об’єднує. Я намагаюся це зробити правильно? Крім того, чи є, можливо, кращий спосіб отримати рядок рядків у відносинах багато-до-багатьох в Eloquent?


Чи перевіряли ви документацію щодо нетерплячого завантаження та методу with? Вашу проблему можна легко вирішити, використовуючи кращий красномовний запит. Опинившись за комп’ютером, я напишу приклад, якщо мене хтось не поб’є.
Luceos

1
@Luceos withне допоможе. Це те, whereHasщо потрібно - як у відповіді нижче.
Ярек Ткачик

так, моя помилка; ви маєте рацію
Luceos

Відповіді:


135

Метод злиття повертає об’єднану колекцію, вона не мутує початкову колекцію, тому вам потрібно зробити наступне

$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
Я намагався скласти плоский список з дерева, використовуючи push, що мені потрібно, але підхід foreach справді допоміг.
Джордж

Майте на увазі, що красномовні колекції поводяться не так, як звичайні колекції, тобто. вони використовують getKeyдля об'єднання результатів, отже,Model::all()->merge(Model::all())->count() === Model::all()->count()
висловився

33

merge()Метод на Collectionне змінює колекцію , на якій він був названий. Він повертає нову колекцію з об’єднаними новими даними. Вам знадобиться:

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

Однак, я думаю, ви вирішуєте проблему з неправильного кута.

Оскільки ви шукаєте питання, які відповідають певним критеріям, можливо, було б легше запитувати таким чином. Методи has()and whereHas()використовуються для створення запиту на основі існування відповідного запису.

Якби ви просто шукали питання, які мають будь-який тег, ви б скористалися has()методом. Оскільки ви шукаєте запитання з певним тегом, ви б використали whereHas()для додавання умови.

Отже, якщо ви хочете, щоб усі запитання, які містять принаймні один тег із позначенням «Подорожі», «Потяги» або «Культура», ваш запит мав би виглядати так:

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

Якщо ви хочете отримати всі запитання, які мали б усі ці три теги, ваш запит мав би виглядати так:

$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
Ярек Ткачик

але ви не можете жорстко кодувати імена тегів. У цьому прикладі у запитання випадково є ці теги, але в інших питаннях теги будуть відрізнятися
Allfarid Morales García 01.03.18

24
$users = User::all();
$associates = Associate::all();

$userAndAssociate = $users->merge($associates);

6
Прочитайте це (перезапис): medium.com/@tadaspaplauskas/…
Jeffz

1
@Jeffz, справді неймовірно, що він об'єднує "дублікати" лише на основі ідентифікатора
andrewtweber

11

Об’єднайте дві різні красномовні колекції в одну, і деякі об’єкти мають однаковий ідентифікатор, один замінить інший. Замість цього використовуйте метод push () або переосмисліть свій підхід до проблеми, щоб уникнути цього. Зверніться до Інтернету


Дякую, це поставило мене до коментаря, знайденого тут medium.com/@jeffparr_57441/…, який, здається, чисто виконує роботу без перезапису.
Позначте

1

У мене не працюють красномовні колекції , красномовні колекції laravel використовують ключ від елементів, які, на мою думку, спричиняють проблеми злиття, вам потрібно повернути першу колекцію як масив, помістити її в нову колекцію, а потім засунути інші в нова колекція;

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

0

Створення нової базової колекції для кожної красномовної колекції об’єднання працює для мене.

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

У цьому випадку не мають конфліктів за його первинними ключами.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.