Uzyskaj określone kolumny za pomocą funkcji „With ()” w Laravel Eloquent

197

Mam dwa stoły Useri Post. Jeden Usermoże mieć wiele postsi jeden postnależący do tylko jednego user.

W moim Usermodelu mam hasManyrelację ...

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

A w moim postmodelu mam belongsTorelację ...

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

Teraz chcę połączyć te dwie tabele za pomocą, Eloquent with()ale chcę konkretnych kolumn z drugiej tabeli. Wiem, że mogę korzystać z Konstruktora zapytań, ale nie chcę.

Kiedy w Postmodelu piszę ...

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

Uruchamia następujące zapytania ...

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

Ale chcę to ...

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

Kiedy używam ...

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

Zwraca tylko kolumnę z pierwszej tabeli. Chcę konkretnych kolumn przy użyciu with()z drugiej tabeli. Jak mogę to zrobić?

Awais Qarni
źródło

Odpowiedzi:

347

Znalazłem rozwiązanie. Można to zrobić, przekazując closurefunkcję with()jako drugi indeks tablicy, takiej jak

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

Wybierze tylko idiz usernameinnej tabeli. Mam nadzieję, że to pomoże innym.


Pamiętaj, że klucz podstawowy (w tym przypadku id) musi być pierwszym parametrem w $ query-> select (), aby faktycznie pobrać niezbędne wyniki. *

Awais Qarni
źródło
1
To dziwne, nie mogłem tego uruchomić. Jak tylko się dodałem $query->select('id','username');, otrzymywałemTrying to get property of non-object
user1669496
5
Dziwne! nadal zwraca wszystkie pola użytkownika. @AwaisQarni
justin
2
Dziękujemy za udostępnienie tego. Gdzie odkryłeś tę możliwość? Nie znalazłem tego w dokumentacji Laravela.
Symen Timmermans
81
Dla tych, którzy to widzą, pamiętaj, że klucz podstawowy ( idw tym przypadku) jest niezbędny, $query->select()aby faktycznie pobrać niezbędne wyniki. Pominąłem to w moim kodzie i nie mogłem zrozumieć, dlaczego nie znalazł żadnych wyników. Głupi ja! Mam nadzieję, że pomoże to każdemu, kto ma ten sam problem
Azirius
4
świetnie, wystarczy dodać klucz obcy, tutaj jego post_id, w przeciwnym razie wynik będzie pusty. Wspomnienie klucza obcego jest tutaj ważne. Dzięki :)
Hashaam Ahmed
102

Możesz to zrobić w ten sposób, ponieważ Laravel 5.5:

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

Dbaj o idpole i foreign keysjak stwierdzono w dokumentach :

Korzystając z tej funkcji, zawsze należy dołączyć kolumnę id i odpowiednie kolumny klucza obcego do listy kolumn, które chcesz pobrać.

Na przykład, jeśli użytkownik należy do zespołu i ma team_idkolumnę jako klucz obcy, wówczas $post->user->teamjest pusty, jeśli nie określono team_id

Post::with('user:id,username,team_id')->get();
Adam
źródło
13
Nie zapomnij podać klucza obcego (zakładając, że tutaj jest post_id), aby rozwiązać relację, w przeciwnym razie otrzymasz puste wyniki dla relacji.
Hashaam Ahmed
2
To naprawdę powinna być wybrana odpowiedź. Działa jak urok :)
Graham,
@Adam, to ograniczy kolumny w tabeli podrzędnej, jak mogę ograniczyć kolumny z tabeli Tabela nadrzędna wraz z tabelą podrzędną?
Sodium
@GauravGenius wszystko, co chcesz ograniczyć od parant belogns w get()metodziePost::with('user:id,username')->get(['age', 'color']);
Adam
82

W twoim Postmodelu

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

Pierwotny kredyt trafia do Laravel Eager Loading - Załaduj tylko określone kolumny

użytkownik1669496
źródło
14
Ale ta relacja sprawi, że będzie tak jak na stałe. W każdych warunkach zawsze zwrócą mi te dwa pola. Może się zdarzyć, że potrzebuję więcej pól w niektórych innych sytuacjach
Awais Qarni,
Następnie musisz użyć konstruktora zapytań.
user1669496,
5
To powinna być zaakceptowana odpowiedź. To jest właściwy sposób, aby to zrobić.
BugHunterUK
1
Czy jest na to sposób w wersji Laravel 5.3? Wydaje mi się, że zmienili to ... znowu .... a teraz, gdy próbuję z takim podejściem, staje się zerowy
Andre F.
Minęło trochę czasu, ale możesz dodać $fieldsparametr.
JordyvD
69

Kiedy idziesz w drugą stronę (hasMany):

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

Nie zapomnij dołączyć klucza obcego (zakładając, że w tym przykładzie jest to user_id), aby rozwiązać relację, w przeciwnym razie uzyskasz zerowe wyniki dla relacji.

Thijs
źródło
6
Tak, dokładnie: „Nie zapomnij dołączyć klucza obcego (zakładając, że w tym przykładzie jest to user_id)”
aqingsao
powinieneś dołączyć kolumnę określającą relację w wybranych polach, w tym przypadku user_id
alimfazeli
Miło złapać brata.
Shahrukh Anwar,
niesamowite bracie, że użycie klucza obcego jest naprawdę ważne, na szczęście widziałem twojego ans, inaczej podrapałbym się w głowę przez wiele godzin. Dzięki!
Hashaam Ahmed
34

W Laravel 5.7 możesz wywoływać określone pola w ten sposób

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

Ważne jest, aby dodać foreign_keypole w zaznaczeniu.

hendra1
źródło
11
nie zapomnij dodać pola klucza obcego
hendra1
2
Nie zapomnij zauważyć komentarza @ hendra1, wszystkie pola klucza obcego są również niezbędne wraz z kluczem podstawowym, w przeciwnym razie otrzymasz pustą kolekcję. Koleś oszczędził mi czas. Dzięki
Rajesh Vishnani,
14

W twoim Postmodelu:

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

Teraz możesz użyć $post->userWithName

Duy Hoang
źródło
2
Naprawdę? Dla mnie to po prostu nic nie zwraca, tzn. Że je psuje?
Sjwdavies
12

Jeśli chcesz uzyskać określone kolumny za pomocą with()elarquent laravela, możesz użyć kodu jak poniżej, na który pierwotnie odpowiedział @Adam w swojej odpowiedzi tutaj w odpowiedzi na to samo pytanie:

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

Użyłem tego w moim kodzie, ale dawało mi to błąd 1052: Column 'id' in field list is ambiguous, więc jeśli macie również ten sam problem

Następnie, aby go rozwiązać, musisz podać nazwę tabeli przed kolumną id w with()metodzie, jak poniżej :

Post::with('user:user.id,username')->get();
Haritsinh Gohil
źródło
Zwraca dla mnie wartość null, ale wcześniej nie wiedziałem, że to możliwe! Ok, więc opublikowałem przedwcześnie, ale znalazłem wynik. Aby użyć tej metody (wygląda na znacznie czystszą), musisz dołączyć link relacji, na przykład kolumnę identyfikatora podczas pobierania danych. Bez tego specyfikatora otrzymasz zerowy zwrot.
Adsy2010
tak @ Adsy2010, aby uzyskać powiązane dane relacji, musisz również uzyskać kolumnę identyfikatora lub klucz podstawowy lub inny identyfikator odpowiedzialny za tę relację.
Haritsinh Gohil
10

Natknąłem się na ten problem, ale z drugą warstwą powiązanych obiektów. Odpowiedź @Awais Qarni utrzymuje się wraz z włączeniem odpowiedniego klucza obcego do zagnieżdżonej instrukcji select. Tak jak identyfikator jest wymagany w pierwszej zagnieżdżonej instrukcji select, aby odwoływać się do powiązanego modelu, tak klucz obcy jest wymagany do odniesienia do drugiego stopnia powiązanych modeli; w tym przykładzie model firmy.

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

Ponadto, jeśli chcesz wybrać określone kolumny z modelu Post, musisz dołączyć kolumnę user_id do instrukcji select, aby móc się do niej odwoływać.

Post::with(['user' => function ($query) {
        $query->select('id', 'username');
    }])
    ->select('title', 'content', 'user_id')
    ->get();
jwarshaw
źródło
4

Zauważ, że jeśli potrzebujesz tylko jednej kolumny z tabeli, użycie „list” jest całkiem przyjemne. W moim przypadku pobieram ulubione artykuły użytkownika, ale chcę tylko identyfikatora artykułu:

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

Zwraca tablicę identyfikatorów, np .:

Array
(
    [0] => 3
    [1] => 7
    [2] => 8
)
omar j
źródło
zwraca kolekcję!
Giovanni Far,
jeśli chcesz tablicy, to zadzwoń toArray()!!! $user->favourites->lists('id')->toArray();
Giovanni Far
Zapytanie nadal otrzyma inne kolumny, ponieważ metoda list () po prostu zmienia tablicę wyników, więc jeśli potrzebujesz tylko „id” z tej tabeli, możesz podać go w zapytaniu. Zawsze dobrze jest pamiętać o wydajności podczas wykonywania zapytań. Miłego kodowania!
Ervin Llojku
-1 $user->favouritespowróci Collectionz wybranymi wszystkimi polami. Prawidłowe stosowanie jest: $user->favourites()->lists('id').
Wallace Maxters
Wybór wszystkiego, aby później użyć filtrowania PHP, jest złym pomysłem. Najlepiej jest używać tylko potrzebnych pól w zapytaniu. Ważne jest, aby znać różnicę między Query\Builder::listsmetodą a Collection::listsmetodą.
Wallace Maxters
1

Możesz także określić kolumny w pokrewnym modelu w momencie dostępu do niego.

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

Shreyansh Panchal
źródło
0

Teraz możesz użyć pluckmetody na Collectioninstancji:

Zwróci tylko uuidatrybutPost model

App\Models\User::find(2)->posts->pluck('uuid')
=> Illuminate\Support\Collection {#983
     all: [
       "1",
       "2",
       "3",
     ],
   }
Giovanni Far
źródło
0

Spróbuj z warunkami.

$id = 1;
Post::with(array('user'=>function($query) use ($id){
    $query->where('id','=',$id);
    $query->select('id','username');
}))->get();
Shirjeel Ahmed Khan
źródło
-3
EmployeeGatePassStatus::with('user:id,name')->get();
kush
źródło
2
Jest to ta sama składnia, co w tej odpowiedzi (tylko inne nazwy modelu i kolumny)
barbsan