Laravel Eloquent: как получить только определенные столбцы из соединенных таблиц


102

У меня есть 2 соединенных таблицы в Eloquent, а именно темы и пользователи.

модель темы:

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

модель пользователя:

public function themes() {
  return $this->has_many('Theme');
}

Мой вызов API Eloquent выглядит следующим образом:

return Response::eloquent(Theme::with('user')->get());

Что возвращает все столбцы из темы (это нормально) и все столбцы от пользователя (не нормально). Мне нужен только столбец «имя пользователя» из пользовательской модели, как я могу ограничить запрос этим?


Я работаю над аналогичной задачей, могу ли я узнать, использую ли я, Responseкакой класс мне нужно импортировать?
Агнес Палит,

Ответы:


103

Измените свою модель, чтобы указать, какие столбцы вы хотите выбрать:

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

И не забудьте указать столбец, к которому вы присоединяетесь.


6
отличный ответ, а также совет о включении столбца соединения сэкономил мне массу времени!
greatwitenorth

Что, если в некоторых местах мне нужен только идентификатор, а не идентификатор и имя пользователя? Все еще нужно выбрать оба?
Darius.V

Привет, имеет ли функция выбора ту же функцию в построителе запросов модели?
Gokigooooks

4
Я не думаю, что это хороший подход. Это будет своего рода жесткое кодирование имен столбцов. Все места вернут только эти столбцы. В некоторых других api мне может понадобиться еще несколько столбцов, так что здесь это не сработает. Я думаю, что здесь можно использовать QueryBuilder.
Аман Сура

2
Это драматический подход, поскольку он будет происходить каждый раз, когда вы продвигаете вызов. Я считаю, что ответ Саджада Ашрафа - это тот, который заинтересует большинство людей.
MMMTroy

37

Для Laravel> = 5.2

Используйте -> Ливер () метод

$roles = DB::table('roles')->pluck('title');

Если вы хотите получить массив, содержащий значения одного столбца, вы можете использовать метод pluck


Для Laravel <= 5.1

Используйте -> списки () метод

$roles = DB::table('roles')->lists('title');

Этот метод вернет массив названий ролей. Вы также можете указать настраиваемый ключевой столбец для возвращаемого массива:


2
На самом деле это не ответ на вопрос (который был конкретно о соединениях / отношениях).
orrd 05

30

Вы можете указать массив полей в параметре get следующим образом:

return Response::eloquent(Theme::with('user')->get(array('user.username'));

ОБНОВЛЕНИЕ (для Laravel 5.2) Из документации вы можете сделать это:

$response = DB::table('themes')
    ->select('themes.*', 'users.username')
    ->join('users', 'users.id', '=', 'themes.user_id')
    ->get();

2
Я пробовал это, и он показывает ошибку, SQLSTATE[42S22]: Column not foundи SQL не включает таблицу в with. В сообщении об ошибке отображается sql «SELECT fk_table.column1 FROM main_table».
Мишель Эйрес,

1
Это «users.username» (а не «user.username»). Код в ответе будет работать, если у вас есть имена таблиц и столбцов, соответствующие вашей реальной базе данных. Обратной стороной этого решения является создание SQL-запроса вместо использования Eloquent, поэтому имена должны соответствовать вашим фактическим таблицам и столбцам базы данных.
orrd 05

22

Я знаю, вы просите Eloquent, но вы можете сделать это с помощью Fluent Query Builder.

$data = DB::table('themes')
    ->join('users', 'users.id', '=', 'themes.user_id')
    ->get(array('themes.*', 'users.username'));

16

Вот как я это делаю

$posts = Post::with(['category' => function($query){
        $query->select('id', 'name');
      }])->get();

Первый ответ пользователя 2317976 не сработал для меня, я использую laravel 5.1


2
Актуальный ответ = полезно!
thesunneversets

Спасибо. Он отлично работает для меня. Я должен добавить внешний ключ в оператор select, как вы это сделали с id, иначе он вернет null.
Иман Седиги

Однако это по-прежнему извлекает "сводное" поле для каждого результата, содержащее оба идентификатора (post_id и category_id), верно? Как я могу на нем ездить?
mayid

1
@mayid, вы можете попробовать добавить pivotв $ hidden массив модели сообщенияprotected $hidden = ['pivot']
Саджад Ашраф

Это лучшее решение (при условии, что вы используете довольно современную версию Laravel)
orrd

11

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

public static $hidden = array('password');

Теперь пароль пользователя будет скрыт, когда вы вернете ответ JSON.

Вы также можете настроить его "на лету" аналогичным образом.

User::$hidden = array('password');

2
в Laravel 4.2 я получаю сообщение «Невозможно получить доступ к защищенному свойству User :: $ hidden» при попытке установить его динамически.
mtmacdonald

1
не должно быть static.
StackOverflowed

@StackOverflowed, насколько я понимаю, вы не заметили, сколько лет этому вопросу / ответу и что он связан с Laravel 3.
Джейсон Льюис

10

Использование с разбивкой на страницы

$data = DB::table('themes')
->join('users', 'users.id', '=', 'themes.user_id')
->select('themes.*', 'users.username')
->paginate(6);

6

user2317976 представил отличный статический способ выбора столбцов связанных таблиц.

Вот динамический трюк, который я нашел, чтобы вы могли получить все, что захотите, используя модель:

return Response::eloquent(Theme::with(array('user' => function ($q) {
    $q->addSelect(array('id','username'))
}))->get();

Я только что обнаружил, что этот трюк также хорошо работает с load (). Это очень удобно.

$queriedTheme->load(array('user'=>function($q){$q->addSelect(..)});

Убедитесь, что вы также указали ключ целевой таблицы, иначе она не сможет его найти.


6

Сюда:

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

Пожалуйста, всегда объясняйте свой ответ.
Рохит Гупта

Была аналогичная проблема, это пока самый умный способ! Этот ответ недооценен!
eldblz

Это то же самое, что и ответ, который ранее уже был представлен Саджадом Ашрафом.
orrd 05

5

Я знаю, что это старый вопрос, но если вы создаете API, как это делает автор вопроса, используйте выходные преобразователи для выполнения таких задач.

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

Я рекомендую Fractal как прочную основу вашего выходного слоя преобразования. Вы можете прочитать документацию здесь .



4

В Laravel 5.5 самый чистый способ сделать это:

Theme::with('user:userid,name,address')->get()

Вы добавляете двоеточие и поля, которые хотите выбрать, через запятую и без пробела между ними.


Вы знаете, как мы можем получить определенный столбец связанной таблицы при использовании разбивки на страницы.
Daniyal Nasir

2

Использование модели:

Model::where('column','value')->get(['column1','column2','column3',...]);

Используя Query Builder:

DB::table('table_name')->where('column','value')->get(['column1','column2','column3',...]);

0

Если я хорошо понял, что возвращается, это нормально, за исключением того, что вы хотите видеть только один столбец. Если это так, то это должно быть намного проще:

return Response::eloquent(Theme::with('user')->get(['username']));

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.