Nhận các cột cụ thể bằng cách sử dụng chức năng với chức năng ()


196

Tôi có hai bảng, UserPost. Một người Usercó thể có nhiều postsvà một chỉ postthuộc về một user.

Trong Usermô hình của tôi, tôi có một hasManymối quan hệ ...

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

Và trong postmô hình của tôi, tôi có một belongsTomối quan hệ ...

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

Bây giờ tôi muốn tham gia hai bảng này bằng cách sử dụng Eloquent with()nhưng muốn các cột cụ thể từ bảng thứ hai. Tôi biết tôi có thể sử dụng Trình tạo truy vấn nhưng tôi không muốn.

Khi trong Postmô hình tôi viết ...

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

Nó chạy các truy vấn sau ...

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

Nhưng điều tôi muốn là ...

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

Khi tôi sử dụng ...

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

Nó chỉ trả về cột từ bảng đầu tiên. Tôi muốn các cột cụ thể sử dụng with()từ bảng thứ hai. Làm thế nào tôi có thể làm điều đó?

Câu trả lời:


345

Vâng, tôi tìm thấy giải pháp. Nó có thể được thực hiện bằng cách chuyển một closurehàm trong with()chỉ mục thứ hai của mảng như

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

Nó sẽ chỉ chọn idusernametừ bảng khác. Tôi hy vọng điều này sẽ giúp những người khác.


Hãy nhớ rằng khóa chính (id trong trường hợp này) cần phải là tham số đầu tiên trong $ query-> select () để thực sự truy xuất các kết quả cần thiết. *


1
Điều đó thật kỳ lạ, tôi không thể làm việc này được. Ngay sau khi tôi thêm vào $query->select('id','username');, tôi đã nhận đượcTrying to get property of non-object
user1669496

5
Kỳ dị! vẫn trả về tất cả các trường của người dùng. @AwaisQarni
justin

2
Cảm ơn vì đã chia sẻ. Bạn đã khám phá ra khả năng này ở đâu? Tôi đã không tìm thấy điều này trong các tài liệu của Laravel.
Symen Timmermans

79
Đối với những người nhìn thấy điều này, hãy nhớ rằng khóa chính ( idtrong trường hợp này) là cần thiết $query->select()để thực sự lấy kết quả cần thiết. Tôi đã bỏ qua mã này trong mã của mình và không thể hiểu tại sao nó không tìm thấy kết quả nào. Tôi thật ngốc! Hy vọng điều này sẽ giúp bất cứ ai khác có cùng vấn đề
Azirius

4
thật tuyệt, chỉ cần thêm khóa ngoại, ở đây post_id nếu không kết quả sẽ trống. Đề cập đến khóa ngoại là quan trọng ở đây. Cảm ơn :)
Hashaam Ahmed

102

Bạn có thể làm điều đó như thế này kể từ Laravel 5.5:

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

Chăm sóc cho các idlĩnh vực và foreign keysnhư đã nêu trong các tài liệu :

Khi sử dụng tính năng này, bạn phải luôn bao gồm cột id và bất kỳ cột khóa ngoại nào có liên quan trong danh sách các cột bạn muốn truy xuất.

Ví dụ: nếu người dùng thuộc về một nhóm và có một team_idcột khóa ngoại, thì $post->user->teamsẽ trống nếu bạn không chỉ định team_id

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

13
Đừng quên bao gồm khóa ngoại (giả sử đó là post_id tại đây) để giải quyết mối quan hệ, nếu không bạn sẽ nhận được kết quả trống cho mối quan hệ của mình.
Hashaam Ahmed

2
Đây thực sự nên là câu trả lời được lựa chọn. Hoạt động như một bùa mê :)
Graham

@Adam, Điều này sẽ hạn chế các cột trong bảng con, làm cách nào tôi có thể hạn chế các cột từ bảng Bảng cha cùng với bảng con?
Natri

@GauravGenius tất cả mọi thứ bạn muốn hạn chế từ các tín hiệu tương đương trong get()phương thứcPost::with('user:id,username')->get(['age', 'color']);
Adam

82

Trong Postmô hình của bạn

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

Tín dụng gốc chuyển đến Laravel Eager Loading - Chỉ tải các cột cụ thể


14
Nhưng mối quan hệ này sẽ làm cho nó giống như mã hóa cứng. Trong mọi điều kiện, nó sẽ luôn trả lại cho tôi hai trường này. Nó có thể xảy ra rằng tôi cần nhiều lĩnh vực hơn trong một số tình huống khác
Awais Qarni

Sau đó, bạn phải sử dụng trình xây dựng truy vấn.
dùng1669496

5
Đây phải là câu trả lời được chấp nhận. Đây là cách chính xác để làm điều đó.
BugHunterUK

1
Có cách nào để làm điều này trong phiên bản Laravel 5.3 không? Tôi nghĩ rằng họ đã thay đổi nó ... một lần nữa .... và bây giờ nó trả về null khi tôi thử với phương pháp này
Andre F.

Đã được một lúc, nhưng bạn có thể thêm một $fieldstham số.
JordyvD

69

Khi đi theo con đường khác (hasMany):

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

Đừng quên bao gồm khóa ngoại (giả sử đó là user_id trong ví dụ này) để giải quyết mối quan hệ, nếu không bạn sẽ không nhận được kết quả nào cho mối quan hệ của mình.


6
Có, chính xác, "Đừng quên bao gồm khóa ngoại (giả sử đó là user_id trong ví dụ này)"
aqingsao

bạn nên bao gồm cột xác định mối quan hệ của bạn trong các trường được chọn, trong trường hợp này là user_id
alimfazeli

Đẹp bắt anh em.
Shahrukh Anwar

Tuyệt vời, việc sử dụng khóa ngoại là rất quan trọng, may mắn là tôi đã thấy ans của bạn nếu không tôi sẽ gãi đầu hàng giờ lol. Cảm ơn người đàn ông!
Hashaam Ahmed

34

Trong Laravel 5.7 bạn có thể gọi trường cụ thể như thế này

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

Điều quan trọng là thêm foreign_keytrường trong lựa chọn.


11
đừng quên thêm trường khóa ngoại
hendra1

2
Đừng quên để ý bình luận của @ hendra1, tất cả các trường khóa ngoại cũng cần thiết cùng với khóa chính, nếu không bạn sẽ nhận được bộ sưu tập trống. Anh chàng tiết kiệm thời gian của tôi. Cảm ơn
Rajesh Vishnani

14

Trong Postmô hình của bạn :

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

Bây giờ bạn có thể sử dụng $post->userWithName


2
Có thật không? Đối với tôi điều này chỉ trả lại không có gì, tức là nó phá vỡ nó?
Sjwdavies

12

Nếu bạn muốn nhận được các cột cụ thể bằng cách sử dụng with()hùng biện laravel thì bạn có thể sử dụng mã như dưới đây được trả lời ban đầu bởi @Adam trong câu trả lời của anh ấy ở đây để trả lời cho cùng câu hỏi này:

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

Vì vậy, tôi đã sử dụng nó trong mã của mình nhưng nó đã gây ra lỗi cho tôi 1052: Column 'id' in field list is ambiguous, vì vậy nếu các bạn cũng gặp phải vấn đề tương tự

Sau đó, để giải quyết nó, bạn phải chỉ định tên bảng trước cột id trongwith() phương thức như mã dưới đây :

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

Điều này trả về null cho tôi nhưng tôi không biết điều này là có thể trước đây! Ok, vì vậy tôi đã đăng Prem Premley nhưng tôi đã tìm thấy một kết quả. Để sử dụng phương pháp này (trông gọn gàng hơn nhiều), bạn phải bao gồm liên kết mối quan hệ, ví dụ cột ID khi kéo dữ liệu. Nếu không có specifier này, bạn sẽ nhận được lợi nhuận null.
Adsy2010

yeah @ Adsy2010, để có được dữ liệu mối quan hệ liên quan, bạn cũng phải lấy cột id hoặc khóa chính hoặc bất kỳ id nào chịu trách nhiệm cho mối quan hệ đó.
Haritsinh Gohil

10

Tôi đã gặp vấn đề này nhưng với một lớp thứ hai của các đối tượng liên quan. Câu trả lời của @Awais Qarni theo kịp với việc đưa khóa ngoại thích hợp vào câu lệnh chọn lồng nhau. Giống như một id được yêu cầu trong câu lệnh chọn lồng nhau đầu tiên để tham chiếu mô hình liên quan, khóa ngoại được yêu cầu để tham chiếu mức độ thứ hai của các mô hình liên quan; trong ví dụ này mô hình Công ty.

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

Ngoài ra, nếu bạn muốn chọn các cột cụ thể từ mô hình Bài đăng, bạn sẽ cần đưa cột user_id vào câu lệnh chọn để tham chiếu nó.

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

4

Lưu ý rằng nếu bạn chỉ cần một cột từ bảng thì sử dụng 'danh sách' là khá tốt. Trong trường hợp của tôi, tôi đang truy xuất các bài viết yêu thích của người dùng nhưng tôi chỉ muốn id của bài viết:

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

Trả về một mảng id, ví dụ:

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

Nó trả lại một bộ sưu tập!
Giovanni Far

nếu bạn muốn một mảng thì hãy gọi toArray()!!! $user->favourites->lists('id')->toArray();
Giovanni Far

Truy vấn vẫn sẽ nhận được các cột khác vì phương thức list () chỉ thay đổi mảng kết quả, vì vậy nếu bạn chỉ cần 'id' từ bảng đó, bạn có thể muốn chỉ định nó trong truy vấn. Luôn luôn là một thói quen tốt để giữ hiệu suất trong tâm trí khi thực hiện các truy vấn. Thưởng thức mã hóa!
Ervininoisjku 11/03/2016

-1 $user->favouritessẽ được trả về Collectionvới tất cả các trường được chọn. Việc sử dụng đúng là : $user->favourites()->lists('id').
Wallace Maxters

Chọn mọi thứ để sử dụng lọc PHP sau này là một ý tưởng tồi. Tốt nhất là chỉ sử dụng các trường cần thiết trong Truy vấn. Điều quan trọng là phải biết sự khác biệt giữa Query\Builder::listsphương pháp và Collection::listsphương pháp.
Wallace Maxters

1

Bạn cũng có thể chỉ định các cột trên mô hình liên quan tại thời điểm truy cập nó.

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


0

Bây giờ bạn có thể sử dụng pluckphương thức trên một Collectionví dụ:

Điều này sẽ chỉ trả lại uuidthuộc tính củaPost model

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

0

Hãy thử với điều kiện.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.