Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select specific columns from Eloquent relations

I have the following models in my application:

User.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function customer_details()
    {
        return $this->hasOne(CustomerDetails::class);
    }
}

CustomerDetails.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class CustomerDetails extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Now I am trying to run the following query:

$user = User::select('email', 'phone')
    ->where('id', Auth::user()->id)
    ->with('customer_details')
    ->first();

Now what I want it to do is to select only the email and phone number from my users table and first_name, last_name from my customer_details table but whenever I try this it always returns customer_details as null.

like image 758
user3718908x100 Avatar asked Dec 24 '22 14:12

user3718908x100


1 Answers

You need to include the id in your select, otherwise the eager loading has nothing to match against. I just tested this against my own project and ran into the same issue, adding the id to the select fixes it.

$user = User::select('id', 'email', 'phone')->where('id', Auth::user()->id)->with('customer_details')->first();

To further explain this, eager loading works by making your parent call first (in this case, the call to users) and then doing a second call like SELECT * FROM customer_details WHERE customer_details.user_id IN (?) where ? is a list of user IDs. It then loops through the results from that second call and attaches them to the appropriate user objects. Without the id on the user objects, there's nothing to match against in the second call or when attaching.

EDIT

To select specific columns from an eagerly loaded table, you can use the closure capabilities explained here. So you use the relationship name as the key and a closure that receives a Builder object as the value, like so:

$user = User::select('id', 'email', 'phone')
    ->where('id', Auth::user()->id)
    ->with('customer_details' => function (Builder $query) {
        $query->select('id', 'user_id', 'name', 'foo');
    })
    ->first();

Note that you must select the relationship column for both, otherwise Laravel has no idea how to connect the two

like image 55
Josh Avatar answered Jan 07 '23 04:01

Josh