รับคอลัมน์เฉพาะโดยใช้ฟังก์ชัน“ With ()” ใน Laravel Eloquent


198

ฉันมีสองตารางและUser Postหนึ่งUserสามารถมีจำนวนมากpostsและเป็นหนึ่งเป็นเพียงคนเดียวpostuser

ในUserแบบจำลองของฉันฉันมีhasManyความสัมพันธ์ ...

public function post(){
    return $this->hasmany('post');
}

และในpostแบบจำลองของฉันฉันมีbelongsToความสัมพันธ์ ...

public function user(){
    return $this->belongsTo('user');
}

ตอนนี้ฉันต้องการเข้าร่วมสองตารางนี้โดยใช้Eloquent with()แต่ต้องการคอลัมน์เฉพาะจากตารางที่สอง ฉันรู้ว่าฉันสามารถใช้ตัวสร้างแบบสอบถามได้ แต่ฉันไม่ต้องการ

เมื่ออยู่ในPostรูปแบบที่ฉันเขียน ...

public function getAllPosts() {
    return Post::with('user')->get();
}

มันเรียกใช้แบบสอบถามต่อไปนี้ ...

select * from `posts`
select * from `users` where `users`.`id` in (<1>, <2>)

แต่สิ่งที่ฉันต้องการคือ ...

select * from `posts`
select id,username from `users` where `users`.`id` in (<1>, <2>)

เมื่อฉันใช้ ...

Post::with('user')->get(array('columns'....));

มันจะส่งกลับคอลัมน์จากตารางแรกเท่านั้น ฉันต้องการคอลัมน์เฉพาะที่ใช้with()จากตารางที่สอง ฉันจะทำสิ่งนั้นได้อย่างไร

คำตอบ:


348

ฉันพบวิธีแก้ปัญหาแล้ว มันสามารถทำได้โดยผ่านclosureฟังก์ชั่นwith()เป็นดัชนีที่สองของอาร์เรย์เช่น

Post::with(array('user'=>function($query){
    $query->select('id','username');
}))->get();

มันจะเลือกidและusernameจากตารางอื่นเท่านั้น ฉันหวังว่านี่จะช่วยผู้อื่น


โปรดจำไว้ว่าคีย์หลัก (id ในกรณีนี้) จะต้องเป็นพารามิเตอร์แรกใน $ query-> select () เพื่อรับผลลัพธ์ที่จำเป็น *


2
มันแปลกฉันไม่สามารถทำงานนี้ได้ ทันทีที่ฉันเพิ่มเข้าไป$query->select('id','username');ฉันได้รับTrying to get property of non-object
user1669496

5
แปลก! ยังคงส่งคืนเขตข้อมูลทั้งหมดของผู้ใช้ @AwaisQarni
justin

2
ขอบคุณสำหรับการแบ่งปัน คุณค้นพบความเป็นไปได้นี้ที่ไหน ฉันไม่พบสิ่งนี้ในเอกสาร Laravel
Symen Timmermans

82
สำหรับผู้ที่เห็นสิ่งนี้จำไว้ว่าคีย์หลัก ( idในกรณีนี้) เป็นสิ่งที่จำเป็นในการที่$query->select()จะเรียกผลลัพธ์ที่จำเป็นจริง ๆ ฉันละเว้นสิ่งนี้ในรหัสของฉันและไม่สามารถระบุได้ว่าเหตุใดจึงไม่พบผลลัพธ์ใด ๆ โง่ฉัน! หวังว่านี่จะช่วยให้คนอื่นที่มีปัญหาเดียวกัน
Azirius

4
เยี่ยมมากเพียงแค่ต้องเพิ่มกุญแจต่างประเทศตรงนี้ post_id มิฉะนั้นผลลัพธ์จะว่างเปล่า การกล่าวถึงกุญแจต่างประเทศเป็นสิ่งสำคัญที่นี่ ขอบคุณ :)
Hashaam Ahmed

105

คุณสามารถทำได้เช่นนี้ตั้งแต่ Laravel 5.5:

Post::with('user:id,username')->get();

สนใจidข้อมูลและforeign keysตามที่ระบุในเอกสาร :

เมื่อใช้คุณสมบัตินี้คุณควรรวมคอลัมน์ id และคอลัมน์สำคัญต่างประเทศที่เกี่ยวข้องในรายการคอลัมน์ที่คุณต้องการเรียกคืน

ตัวอย่างเช่นหากผู้ใช้เป็นสมาชิกของทีมและมีteam_idคอลัมน์คีย์ต่างประเทศแสดงว่า$post->user->teamว่างเปล่าถ้าคุณไม่ระบุ team_id

Post::with('user:id,username,team_id')->get();

13
อย่าลืมใส่รหัสต่างประเทศ (สมมติว่ามันคือ post_id ที่นี่) เพื่อแก้ไขความสัมพันธ์มิฉะนั้นคุณจะได้รับผลลัพธ์ที่ว่างเปล่าสำหรับความสัมพันธ์ของคุณ
Hashaam Ahmed

2
นี่ควรเป็นคำตอบที่เลือกจริงๆ ใช้งานได้เหมือนมีเสน่ห์ :)
เกรแฮม

@Adam สิ่งนี้จะ จำกัด คอลัมน์ในตารางลูกฉันจะ จำกัด คอลัมน์จากตารางตารางผู้ปกครองพร้อมกับตารางลูกได้อย่างไร
โซเดียม

@GauravGenius ทุกสิ่งที่คุณต้องการ จำกัด จากผู้ปกครองที่ไม่ระบุตัวตนในget()วิธีการPost::with('user:id,username')->get(['age', 'color']);
Adam

82

ในPostแบบของคุณ

public function user()
{
    return $this->belongsTo('User')->select(array('id', 'username'));
}

เครดิตเริ่มต้นไปที่การโหลดแบบคลื่น Laravel - โหลดคอลัมน์ที่เฉพาะเจาะจงเท่านั้น


14
แต่ความสัมพันธ์นี้จะทำให้เหมือนฮาร์ดโค้ด ในทุกสภาวะมันจะคืนค่าฟิลด์ทั้งสองนี้ให้ฉันเสมอ อาจเกิดขึ้นที่ฉันต้องการเขตข้อมูลเพิ่มเติมในบางสถานการณ์
Awais Qarni

จากนั้นคุณต้องใช้ตัวสร้างแบบสอบถาม
user1669496

5
นี่ควรเป็นคำตอบที่ยอมรับได้ นี่เป็นวิธีที่ถูกต้องที่จะทำ
BugHunterUK

1
มีวิธีทำเช่นนี้ในรุ่น Laravel 5.3 หรือไม่? ฉันคิดว่าพวกเขาเปลี่ยนมัน ... อีกครั้ง .... และตอนนี้มันกลับเป็นโมฆะเมื่อฉันลองใช้วิธีนี้
Andre F.

ไม่นานมานี้ แต่คุณสามารถเพิ่ม$fieldsพารามิเตอร์ได้
JordyvD

69

เมื่อไปทางอื่น (มีหลายคน):

User::with(array('post'=>function($query){
    $query->select('id','user_id');
}))->get();

อย่าลืมใส่รหัสต่างประเทศ (สมมติว่าเป็น user_id ในตัวอย่างนี้) เพื่อแก้ไขความสัมพันธ์มิฉะนั้นคุณจะได้ผลลัพธ์เป็นศูนย์สำหรับความสัมพันธ์ของคุณ


6
ใช่ว่า "อย่าลืมใส่รหัสต่างประเทศ (สมมติว่าเป็น user_id ในตัวอย่างนี้)"
aqingsao

คุณควรรวมคอลัมน์ที่กำหนดความสัมพันธ์ของคุณในฟิลด์ที่เลือกในกรณีนี้ user_id
alimfazeli

พี่ชายจับนิสัยดี
Shahrukh Anwar

พี่ชายที่ยอดเยี่ยมการใช้คีย์ต่างประเทศนั้นสำคัญมากโชคดีที่ฉันเห็นคำตอบของคุณไม่เช่นนั้นฉันจะเกาหัวเป็นเวลาหลายชั่วโมงฮ่า ๆ ๆ ขอบคุณคน!
Hashaam Ahmed

35

ใน Laravel 5.7 คุณสามารถเรียกใช้ฟิลด์เฉพาะเช่นนี้ได้

$users = App\Book::with('author:id,name')->get();

มันเป็นสิ่งสำคัญที่จะเพิ่มforeign_keyสนามในการเลือก


12
อย่าลืมเพิ่มเขตข้อมูลคีย์ต่างประเทศ
hendra1

2
อย่าลืมที่จะสังเกตเห็นความคิดเห็นของ @ hendra1 เขตข้อมูลคีย์ต่างประเทศทั้งหมดนั้นจำเป็นพร้อมกับคีย์หลักไม่เช่นนั้นคุณจะได้รับคอลเล็กชันว่าง เพื่อนช่วยประหยัดเวลาของฉัน ขอบคุณ
Rajesh Vishnani

14

ในPostรูปแบบของคุณ:

public function userWithName()
{
    return $this->belongsTo('User')->select(array('id', 'first_name', 'last_name'));
}

ตอนนี้คุณสามารถใช้ $post->userWithName


2
จริงๆ? สำหรับฉันแล้วมันไม่ได้ผลตอบแทนอะไรเลย
Sjwdavies

12

หากคุณต้องการรับคอลัมน์เฉพาะที่ใช้with()ใน laravel eloquent คุณสามารถใช้โค้ดด้านล่างซึ่ง @Adam ตอบกลับมาโดยเริ่มแรกในคำตอบของเขาที่นี่เพื่อตอบคำถามเดียวกันนี้:

Post::with('user:id,username')->get();

ดังนั้นฉันได้ใช้มันในรหัสของฉันแต่มันก็ให้ฉันข้อผิดพลาดของ1052: Column 'id' in field list is ambiguous,ดังนั้นถ้าพวกคุณยังต้องเผชิญปัญหาเดียวกัน

จากนั้นสำหรับการแก้ปัญหาคุณจะต้องระบุชื่อตารางก่อนคอลัมน์ id ในwith()วิธีการดังต่อไปนี้รหัส :

Post::with('user:user.id,username')->get();

คืนนี้เป็นโมฆะสำหรับฉัน แต่ฉันไม่รู้ว่ามันเป็นไปได้มาก่อน! ตกลงดังนั้นฉันโพสต์ก่อนเวลาอันควร แต่ฉันพบผลลัพธ์ หากต้องการใช้วิธีนี้ (ดูสะอาดกว่ามาก) คุณต้องรวมลิงก์ความสัมพันธ์ไว้เช่นคอลัมน์ ID เมื่อดึงข้อมูลด้วย หากไม่มีตัวระบุนี้คุณจะได้รับผลตอบแทนที่เป็นโมฆะ
Adsy2010

yeah @ Adsy2010 สำหรับการรับข้อมูลความสัมพันธ์ที่เกี่ยวข้องคุณต้องได้รับคอลัมน์ id หรือคีย์หลักหรือรหัสใดก็ตามที่รับผิดชอบความสัมพันธ์นั้น
Haritsinh Gohil

10

ฉันเจอปัญหานี้ แต่มีเลเยอร์ที่สองของวัตถุที่เกี่ยวข้อง @Awais คำตอบของ Qarni ถือได้ว่าเป็นการรวมคีย์ต่างประเทศที่เหมาะสมไว้ในคำสั่ง Select แบบซ้อน เช่นเดียวกับจำเป็นต้องมี id ในคำสั่ง select ที่ซ้อนกันแรกเพื่ออ้างอิงโมเดลที่เกี่ยวข้องจำเป็นต้องมี foreign key เพื่ออ้างอิงระดับที่สองของโมเดลที่เกี่ยวข้อง ในตัวอย่างนี้รูปแบบ บริษัท

Post::with(['user' => function ($query) {
        $query->select('id','company_id', 'username');
    }, 'user.company' => function ($query) {
        $query->select('id', 'name');
    }])->get();

นอกจากนี้หากคุณต้องการเลือกคอลัมน์เฉพาะจากโมเดลโพสต์คุณจะต้องรวมคอลัมน์ user_id ในคำสั่ง select เพื่อใช้อ้างอิง

Post::with(['user' => function ($query) {
        $query->select('id', 'username');
    }])
    ->select('title', 'content', 'user_id')
    ->get();

4

โปรดทราบว่าหากคุณต้องการเพียงหนึ่งคอลัมน์จากตารางการใช้ 'รายการ' นั้นค่อนข้างดี ในกรณีของฉันฉันกำลังค้นหาบทความโปรดของผู้ใช้ แต่ฉันต้องการเฉพาะหมายเลขบทความ:

$favourites = $user->favourites->lists('id');

ส่งคืนอาร์เรย์ของรหัสเช่น:

Array
(
    [0] => 3
    [1] => 7
    [2] => 8
)

มันกลับคอลเลกชัน!
Giovanni Far

ถ้าคุณต้องการอาร์เรย์แล้วโทรtoArray()!!! $user->favourites->lists('id')->toArray();
Giovanni Far

แบบสอบถามจะยังคงได้รับคอลัมน์อื่น ๆ เนื่องจากรายการ () วิธีการเพียงแค่เปลี่ยนอาร์เรย์ผลลัพธ์ดังนั้นหากคุณต้องการ 'id' จากตารางนั้นคุณอาจต้องการระบุในแบบสอบถาม เป็นนิสัยที่ดีในการรักษาประสิทธิภาพเมื่อคำนึงถึงการสืบค้น เพลิดเพลินกับการเข้ารหัส!
Ervin Llojku

-1 $user->favouritesจะกลับมาCollectionพร้อมกับทุกช่องที่เลือก การใช้ที่ถูกต้องคือ: $user->favourites()->lists('id').
Wallace Maxters

การเลือกทุกอย่างเพื่อใช้การกรอง PHP ในภายหลังเป็นแนวคิดที่ไม่ดี เป็นการดีที่สุดที่จะใช้เฉพาะเขตข้อมูลที่จำเป็นในแบบสอบถาม สิ่งสำคัญคือต้องทราบความแตกต่างระหว่างQuery\Builder::listsวิธีการและCollection::listsวิธีการ
Wallace Maxters

1

นอกจากนี้คุณยังสามารถระบุคอลัมน์ในโมเดลที่เกี่ยวข้องในเวลาที่เข้าถึงได้

Post::first()->user()->get(['columns....']);


0

ตอนนี้คุณสามารถใช้pluckวิธีการกับCollectionอินสแตนซ์:

สิ่งนี้จะส่งคืนเฉพาะแอuuidททริบิวของPost model

App\Models\User::find(2)->posts->pluck('uuid')
=> Illuminate\Support\Collection {#983
     all: [
       "1",
       "2",
       "3",
     ],
   }


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