Получить определенные столбцы, используя функцию «With ()» в Laravel Eloquent

198

У меня есть две таблицы, Userи Post. У одного Userможет быть много, postsа у одного post- только один user.

В моей Userмодели у меня есть hasManyотношение ...

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

И в моей postмодели у меня есть belongsToотношение ...

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

Теперь я хочу объединить эти две таблицы, используя Eloquent with()отдельные столбцы из второй таблицы. Я знаю, что могу использовать Query Builder, но не хочу.

Когда в 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()из второй таблицы. Как я могу это сделать?

Авайс Карни
источник

Ответы:

349

Ну, я нашел решение. Это можно сделать, передав 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
Weird! по-прежнему возвращает все поля пользователя. @AwaisQarni
джастин
2
Спасибо за то, что поделился этим. Где вы обнаружили эту возможность? Я не нашел этого в документах Laravel.
Симен Тиммерманс
82
Для тех, кто видит это, помните, что первичный ключ ( idв данном случае) необходим $query->select()для фактического получения необходимых результатов. Я пропустил это в своем коде и не мог понять, почему он не даст никаких результатов. Я такой глупый! Надеюсь, что это поможет кому-то еще с той же проблемой
Азириус
4
отлично, просто нужно добавить внешний ключ, здесь его post_id, иначе результат будет пустым. Упоминание внешнего ключа здесь важно. Спасибо :)
Хашам Ахмед
106

Вы можете сделать это так с 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 здесь), чтобы разрешить отношение, иначе вы получите пустые результаты для вашего отношения.
Хашам Ахмед
2
Это действительно должен быть выбранный ответ. Работает как очарование :)
Грэм
@Adam, это будет ограничивать столбцы в дочерней таблице, как я могу ограничить столбцы из таблицы родительской таблицы вместе с дочерней таблицей?
Натрий
@GauravGenius все, что вы хотите ограничить из-за притчи в get()методеPost::with('user:id,username')->get(['age', 'color']);
Адам
82

В вашей Postмодели

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

Оригинальный кредит переходит к Laravel Eager Загрузка - Загрузка только определенных столбцов

user1669496
источник
14
Но это отношение сделает его таким же жестко закодированным. При всех условиях он всегда вернет мне эти два поля. Может случиться так, что мне нужно больше полей в некоторых других ситуациях
Awais Qarni
Тогда вы должны использовать построитель запросов.
user1669496
5
Это должен быть принятый ответ. Это правильный способ сделать это.
BugHunterUK
1
Есть ли способ сделать это в версии Laravel 5.3? Я думаю, что они изменили это ... снова .... и теперь это возвращает нуль, когда я пытаюсь с этим подходом
Андре Ф.
Это было давно, но вы могли бы добавить $fieldsпараметр.
JordyvD
70

При переходе в другую сторону (hasMany):

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

Не забудьте включить внешний ключ (при условии, что в этом примере это user_id) для разрешения отношения, иначе вы получите нулевой результат для вашего отношения.

Тайс
источник
6
Да, именно: «Не забудьте включить внешний ключ (при условии, что в этом примере это user_id)»
aqingsao
Вы должны включить столбец, который определяет ваши отношения в выбранных полях, в этом случае user_id
alimfazeli
Приятно поймать брата.
Шахрух Анвар
Круто, братан, что использование внешнего ключа действительно важно, к счастью, я видел твои ответы, иначе я бы почесал голову часами. Спасибо чувак!
Хашам Ахмед
35

В Laravel 5.7 вы можете называть определенное поле следующим образом

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

Важно добавить foreign_keyполе в выделение.

hendra1
источник
12
не забудьте добавить поле внешнего ключа
hendra1
2
Не забудьте заметить комментарий @ hendra1, все поля внешнего ключа также необходимы вместе с первичным ключом, в противном случае вы получите пустую коллекцию. Чувак сэкономил мое время. Спасибо
Раджеш Вишнани
14

В вашей Postмодели:

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

Теперь вы можете использовать $post->userWithName

Дуй Хоанг
источник
2
В самом деле? Для меня это просто ничего не возвращает, т.е. это ломает?
Sjwdavies
12

Если вы хотите , чтобы получить определенные столбцы , используя with()в Laravel красноречивы , то вы можете использовать код , как показано ниже , который первоначально ответили @Adam в своем ответе здесь в ответ на этот же вопрос:

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

Так что я использовал его в своем коде, но он выдавал ошибку 1052: Column 'id' in field list is ambiguous, поэтому, если вы, ребята, тоже столкнулись с той же проблемой

Затем для ее решения необходимо указать имя таблицы перед столбцом id в with()методе, как показано ниже :

Post::with('user:user.id,username')->get();
Харицинь Гохил
источник
Это возвращает ноль для меня, но я не знал, что это было возможно раньше! Итак, я разместил prematurley, но я нашел результат. Чтобы использовать этот метод (выглядит намного чище), вы должны включить ссылку на связь, например, столбец ID при извлечении данных. Без этого спецификатора вы получите нулевой возврат.
Adsy2010
да @ Adsy2010, для получения связанных данных о взаимоотношениях вы также должны получить столбец идентификатора или первичный ключ или любой другой идентификатор, который отвечает за эти отношения.
Харицин Гохил
10

Я сталкивался с этой проблемой, но со вторым слоем связанных объектов. Ответ @Awais Qarni имеет место с включением соответствующего внешнего ключа во вложенный оператор выбора. Так же, как идентификатор требуется в первом вложенном операторе выбора для ссылки на связанную модель, внешний ключ необходим для ссылки на вторую степень связанных моделей; в этом примере модель компании.

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

Кроме того, если вы хотите выбрать конкретные столбцы из модели Post, вам нужно будет включить столбец user_id в оператор выбора, чтобы ссылаться на него.

Post::with(['user' => function ($query) {
        $query->select('id', 'username');
    }])
    ->select('title', 'content', 'user_id')
    ->get();
jwarshaw
источник
4

Обратите внимание, что если вам нужен только один столбец из таблицы, тогда использование списков - это неплохо. В моем случае я получаю любимые статьи пользователя, но мне нужны только идентификаторы статей:

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

Возвращает массив идентификаторов, например:

Array
(
    [0] => 3
    [1] => 7
    [2] => 8
)
Омар Дж
источник
это вернуть коллекцию!
Джованни Фар
если вы хотите массив, то вызовите toArray()!!! $user->favourites->lists('id')->toArray();
Джованни Фар
Запрос все равно получит другие столбцы, потому что метод list () просто меняет массив результатов, поэтому, если вам просто нужен идентификатор из этой таблицы, вы можете указать его в запросе. Всегда полезно помнить о производительности при выполнении запросов. Наслаждайтесь кодированием!
Эрвин Ллойку
-1 $user->favouritesбудет возвращено Collectionсо всеми выбранными полями. Правильное использование: $user->favourites()->lists('id').
Уоллес Макстерс
Выбор всего для последующего использования фильтрации PHP - плохая идея. Лучше всего использовать только необходимые поля в Query. Важно знать разницу между Query\Builder::listsметодом и Collection::listsметодом.
Уоллес Макстерс
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",
     ],
   }
Джованни Фар
источник
0

Попробуйте с условиями.

$id = 1;
Post::with(array('user'=>function($query) use ($id){
    $query->where('id','=',$id);
    $query->select('id','username');
}))->get();
Ширджил Ахмед Хан
источник
-3
EmployeeGatePassStatus::with('user:id,name')->get();
Куш
источник
2
Это тот же синтаксис, что и в этом ответе (только разные имена для модели и столбца)
Барбсан