วิธีการรวมคอลเลกชันที่คมชัดสองชุด


87

ฉันมีตารางคำถามและตารางแท็ก ฉันต้องการดึงคำถามทั้งหมดจากแท็กของคำถามที่ระบุ ตัวอย่างเช่นฉันอาจมีแท็ก "การเดินทาง" "รถไฟ" และ "วัฒนธรรม" แนบไปกับคำถามที่ระบุ ฉันต้องการดึงคำถามทั้งหมดสำหรับแท็กทั้งสามนี้ ดูเหมือนว่าจะยุ่งยากก็คือความสัมพันธ์ของคำถามและแท็กเป็นแบบกลุ่มต่อกลุ่มที่กำหนดไว้ใน Eloquent เป็นเป็นของ

ฉันคิดว่าจะพยายามรวมคอลเลกชันคำถามดังต่อไปนี้:

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

ดูเหมือนจะไม่ได้ผล ดูเหมือนจะไม่รวมอะไรเลย ฉันพยายามอย่างถูกต้องหรือไม่? นอกจากนี้อาจมีวิธีที่ดีกว่าในการเรียกแถวของความสัมพันธ์แบบกลุ่มต่อกลุ่มใน Eloquent หรือไม่?


คุณได้ตรวจสอบเอกสารเกี่ยวกับการโหลดอย่างกระตือรือร้นและวิธีการด้วยหรือไม่? ปัญหาของคุณสามารถแก้ไขได้อย่างง่ายดายโดยใช้ข้อความค้นหาที่คมคายดีกว่า เมื่อฉันอยู่ข้างหลังคอมพิวเตอร์ฉันจะเขียนตัวอย่างเว้นแต่จะมีคนเอาชนะฉันไป
Luceos

1
@Luceos withจะไม่ช่วย มันwhereHasเป็นสิ่งที่จำเป็น - เช่นในคำตอบดังต่อไปนี้
Jarek Tkaczyk

ใช่ความผิดพลาดของฉัน คุณถูกต้อง
Luceos

คำตอบ:


139

วิธีการผสานจะส่งคืนคอลเล็กชันที่ผสาน แต่จะไม่กลายพันธุ์คอลเลกชันดั้งเดิมดังนั้นคุณต้องทำสิ่งต่อไปนี้

$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 ช่วยได้มาก
George

โปรดทราบว่าคอลเลกชันที่มีคุณภาพไม่ทำงานเหมือนคอลเล็กชันปกติกล่าวคือ พวกเขาใช้getKeyเพื่อรวมผลลัพธ์ดังนั้นModel::all()->merge(Model::all())->count() === Model::all()->count()
ส่ง

34

merge()วิธีการเกี่ยวกับการCollectionไม่ได้ปรับเปลี่ยนคอลเลกชันที่มันถูกเรียกว่า ส่งคืนคอลเล็กชันใหม่พร้อมกับข้อมูลใหม่ที่รวมเข้าด้วยกันคุณจะต้อง:

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

อย่างไรก็ตามฉันคิดว่าคุณกำลังแก้ปัญหาจากมุมที่ไม่ถูกต้อง

เนื่องจากคุณกำลังมองหาคำถามที่ตรงตามเกณฑ์ที่กำหนดจึงน่าจะง่ายกว่าที่จะสอบถามในลักษณะนั้น has()และ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
+ อย่างไรก็ตามตัวเลือกที่ 2 (แท็กทั้งหมด) ที่คุณแนะนำอาจทำให้ง่ายขึ้น: stackoverflow.com/a/24706347/784588
Jarek Tkaczyk

แต่คุณไม่สามารถฮาร์ดโค้ดชื่อแท็กได้ ในตัวอย่างนี้คำถามมีแท็กเหล่านี้ แต่ในคำถามอื่น ๆ แท็กจะแตกต่างกันไป
Allfarid Morales García

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

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

6
อ่านสิ่งนี้ (เขียนทับ): medium.com/@tadaspaplauskas/…
Jeffz

1
@Jeffz ไม่น่าเชื่อจริงๆว่ามันรวม "รายการที่ซ้ำกัน" ตาม ID เพียงอย่างเดียว
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;
}

1

การสร้างคอลเลกชันพื้นฐานใหม่สำหรับคอลเลกชันที่มีฝีปากแต่ละคอลเลกชั่นการผสานใช้ได้กับฉัน

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

ในกรณีนี้ไม่มีคีย์หลักที่เชื่อมโยงกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.