İki Güzel Koleksiyon Nasıl Birleştirilir?


87

Soru tablom ve etiketler tablom var. Verilen bir sorunun etiketlerinden tüm soruları almak istiyorum. Dolayısıyla, örneğin, belirli bir soruya "Seyahat", "Trenler" ve "Kültür" etiketlerini ekleyebilirim. Bu üç etiket için tüm soruları getirebilmek istiyorum. Görünüşe göre zor olan, sorular ve etiketler ilişkisinin Eloquent'te ownToMany olarak tanımlanan çoka çok olmasıdır.

Soru Koleksiyonlarını aşağıdaki gibi birleştirmeye çalışmayı düşündüm:

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

Yine de işe yaramıyor gibi görünüyor. Hiçbir şeyi birleştirmiyor gibi görünüyor. Bunu doğru deniyor muyum? Ayrıca, Eloquent'te çoka çok ilişkisinde bir satır satırı getirmenin daha iyi bir yolu olabilir mi?


İstekli yükleme ve kullanma yöntemiyle ilgili belgeleri kontrol ettiniz mi? Sorununuz daha iyi anlamlı bir sorgu kullanılarak kolayca çözülebilir. Bir bilgisayarın arkasına geçtiğimde, birisi beni dövmediği sürece bir örnek yazacağım.
Luceos

1
@Luceos withyardımcı olmayacak. İşte whereHasgerekli - aşağıdaki cevapta olduğu gibi.
Jarek Tkaczyk

evet benim hatam; Eğer doğru
Luceos

Yanıtlar:


139

Birleştirme yöntemi birleştirilmiş koleksiyonu döndürür, orijinal koleksiyonu değiştirmez, bu nedenle aşağıdakileri yapmanız gerekir

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

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

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

Örneği kodunuza uygulama

$related = new Collection();

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

1
Bir ağaçtan düz bir liste oluşturmaya çalışıyordum, itme kullanarak ihtiyacım olan şeydi, ancak foreach yaklaşımı gerçekten yardımcı oldu.
George

Eloquent koleksiyonlarının normal Koleksiyonlar gibi davranmadığını unutmayın, yani. getKeysonuçları birleştirmek için kullandıkları içinModel::all()->merge(Model::all())->count() === Model::all()->count()
2020

34

Üzerindeki merge()yöntem Collectionçağrıldığı koleksiyonu değiştirmez. Yeni verilerin birleştirildiği yeni bir koleksiyon döndürür. Şunlara ihtiyacınız olacaktır:

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

Ancak, sorunu yanlış açıdan ele aldığınızı düşünüyorum.

Belirli bir kriteri karşılayan sorular aradığınız için, bu şekilde sorgulamak muhtemelen daha kolay olacaktır. has()Ve whereHas()yöntemleri, ilgili kayıt varlığına dayalı bir sorgu oluşturmak için kullanılır.

Sadece herhangi bir etiketi olan soruları arıyor olsaydın, has()yöntemi kullanırdın . Belirli bir etikete sahip sorular aradığınız için whereHas()koşulu eklemek için öğesini kullanırsınız .

Dolayısıyla, 'Seyahat', 'Trenler' veya 'Kültür' ile en az bir etiketi olan tüm soruları istiyorsanız, sorgunuz şöyle görünecektir:

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

Bu etiketlerin üçünü de içeren tüm soruları istiyorsanız, sorgunuz şöyle görünecektir:

$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
+, ancak önerdiğiniz 2. (tüm etiketler) seçeneği basitleştirilebilir: stackoverflow.com/a/24706347/784588
Jarek Tkaczyk

ancak etiket adlarını sabit kodlayamazsınız. Bu örnekte, soruda bu etiketler var, ancak diğer sorularda etiketler değişiklik gösterecek
Allfarid Morales García


11

İki farklı anlamlı koleksiyonu bir araya getirin ve bazı nesneler aynı kimliğe sahip olur, biri diğerinin üzerine yazılır. Bunun yerine push () yöntemini kullanın veya bundan kaçınmak için soruna yaklaşımınızı yeniden düşünün. Web'e bakın


Teşekkürler, bu beni, üzerine yazmadan işi temiz bir şekilde yapıyor gibi görünen medium.com/@jeffparr_57441/… burada bulunan yoruma koydu .
Mark

1

Her şey benim için anlamlı koleksiyonlarda işe yaramıyor , laravel anlamlı koleksiyonlar, birleşme sorunlarına neden olduğunu düşündüğüm öğelerin anahtarını kullanıyor , ilk koleksiyonu bir dizi olarak geri almanız, onu yeni bir koleksiyona koymanız ve ardından diğerlerini içeri itmeniz gerekiyor. yeni koleksiyon;

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

1

Her anlamlı koleksiyon için yeni bir temel koleksiyon oluşturmak, birleştirme benim için işe yarıyor.

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

Bu durumda birincil anahtarlarına göre conflits'e sahip değilsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.