Come unire due raccolte eloquenti?


87

Ho una tabella delle domande e una tabella dei tag. Voglio recuperare tutte le domande dai tag di una determinata domanda. Quindi, ad esempio, potrei avere i tag "Viaggi", "Treni" e "Cultura" associati a una determinata domanda. Voglio essere in grado di recuperare tutte le domande per questi tre tag. Il difficile, così sembra, è che la relazione tra domande e tag è un molti-a-molti definito in Eloquent come appartiene a molti.

Ho pensato di provare a unire le raccolte di domande come di seguito:

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

Tuttavia non sembra funzionare. Non sembra fondere nulla. Sto tentando di farlo correttamente? Inoltre, esiste forse un modo migliore per recuperare una fila di righe in una relazione molti-a-molti in Eloquent?


Hai controllato la documentazione sul caricamento ansioso e sul metodo with? Il tuo problema potrebbe essere facilmente risolto utilizzando una query eloquente migliore. Una volta che mi trovo dietro un computer scriverò un esempio a meno che qualcuno non mi battesse.
Luceos

1
@Luceos withnon aiuterà. È whereHasnecessario, come nella risposta sotto.
Jarek Tkaczyk

sì, errore mio; hai ragione
Luceos

Risposte:


139

Il metodo merge restituisce la raccolta unita, non modifica la raccolta originale, quindi è necessario eseguire le seguenti operazioni

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

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

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

Applicare l'esempio al codice

$related = new Collection();

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

1
Stavo cercando di creare un elenco semplice da un albero, usando push era ciò di cui avevo bisogno, ma l'approccio foreach mi ha davvero aiutato.
George,

Tieni presente che le raccolte eloquenti non si comportano come le normali raccolte, ad es. usano getKeyper unire i risultati, quindiModel::all()->merge(Model::all())->count() === Model::all()->count()
eithed l'

34

Il merge()metodo su Collectionnon modifica la raccolta su cui è stato chiamato. Restituisce una nuova raccolta con i nuovi dati uniti. Avresti bisogno di:

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

Tuttavia, penso che tu stia affrontando il problema dall'angolazione sbagliata.

Poiché stai cercando domande che soddisfano determinati criteri, probabilmente sarebbe più facile interrogare in questo modo. I metodi has()e whereHas()vengono utilizzati per generare una query basata sull'esistenza di un record correlato.

Se cercavi solo domande con tag, utilizzeresti il has()metodo. Poiché stai cercando domande con un tag specifico, utilizzeresti whereHas()per aggiungere la condizione.

Quindi, se desideri tutte le domande che hanno almeno un tag con "Viaggio", "Treni" o "Cultura", la tua query sarà simile a:

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

Se desideri tutte le domande che contengono tutti e tre questi tag, la tua query sarà simile a:

$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
+, tuttavia la seconda opzione (tutti i tag) che hai suggerito potrebbe essere semplificata: stackoverflow.com/a/24706347/784588
Jarek Tkaczyk

ma non puoi codificare i nomi dei tag. In questo esempio, la domanda ha quei tag, ma in altre domande i tag varieranno
Allfarid Morales García


11

Unisci due diverse raccolte eloquenti in una e alcuni oggetti hanno lo stesso ID, uno sovrascriverà l'altro. Usa invece il metodo push () o ripensa il tuo approccio al problema per evitarlo. Fare riferimento al web


Grazie, questo mi ha messo sul commento trovato qui medium.com/@jeffparr_57441/… che sembra fare il lavoro in modo pulito senza sovrascrivere.
Marco

1

Non tutto funziona per me su raccolte eloquenti , le raccolte eloquenti di laravel usano la chiave degli elementi che penso che causino problemi di fusione, è necessario recuperare la prima raccolta come array, inserirla in una nuova raccolta e quindi inserire le altre la nuova collezione;

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

1

Creando una nuova collezione di base per ogni raccolta eloquente, l'unione funziona per me.

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

In questo caso non avere conflitti per le sue chiavi primarie.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.