Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Load specific columns from eager loaded laravel collection [duplicate]

Consider books and authors relationship. Every book belongsTo an author and 1 author hasMany books. Books table has fields like (Id,Title,Version etc) and authors have fields like (Id,Name,Address etc). Note DB columns do not follow the default laravel naming convention.

Now; I want to fetch some fields from both tables. More speficic, I want title,version,name and address fields. This is desired output:

    {
        Title: "Oxford Maths",
        Version: "2.5",
        author: "John Doe",
    }

1st trial:

return Book::with('author')->get()->map(function ($book) {
    return collect($book)->only(
        [
            'Title',
            'Version',
            "author"
        ]);
});

1st Trial Output:

    {
        Title: "Oxford Maths",
        Version: "2.5",
        author: {
            Id: 1,
            Name: "John Doe",
            Address: "Tanzania",
            deleted_at: null
        }
    }

2nd trial: Tried this;

return Book::with([
        'author' => function($query){
            $query->select('Name','Id');
        }
    ])->get()->map(function ($data) {
    return collect($data)->only(
        [
            'Title',
            'Version',
            "author"
        ]);
});

And this;

return Book::with('authority:name,Id')->get()->map(function ($data) {
    return collect($data)->only(
        [
            'Title',
            'Version',
            "author"
        ]);
});

2nd Trial output:

    {
        Title: "Oxford Maths",
        Version: "2.5",
        author: {
            Name: "John Doe",
            Id: 1
        }
    }

3rd Trial:

return Book::with([
        'author' => function($query){
            $query->select('Name'); // *Removed foreignKey*
        }
    ])->get()->map(function ($data) {
    return collect($data)->only(
        [
            'Title',
            'Version',
            "author"
        ]);
});

3rd Trial output:

    {
        Title: "Oxford Maths",
        Version: "2.5",
        author: null
    }

What can I do to get the desired output?

like image 886
Mussa Moses Avatar asked Dec 07 '25 06:12

Mussa Moses


2 Answers

Of course, you can do it afterwards on the collection but it makes more sense to do it directly on the query. You try to reflect that in your 3rd trial. However, in my opinion that's were Laravel behaves a bit odd. In order to do the eager loading, you need your foreign key. Even though, that's logical, it's human to forget about that nevertheless. But if you forget to include the foreign key, Laravel doesn't tell you this and instead returns null. So make sure, all necessary primary and foreign keys are always included in your relation.

return Book::with([
    'author' => function($query){
        $query->select('id', 'Name'); // *Removed foreignKey*
    }
])->get([ 'title' , 'version' ]);

One thing, I like to do when a relation should mostly return only one of its values:

class Author extends Model
{
    public function __toString()
    {
        return $this->Name;
    }
}

To make this automatically serialized this way, you can change __toString() to jsonSerialize()

class Author extends Model implements JsonSerializable
{
    public function jsonSerialize()
    {
        return $this->Name;
    }
}
like image 194
shaedrich Avatar answered Dec 08 '25 20:12

shaedrich


Maybe it will help you

in Model

protected $appends = [
    'author_name', 'address'
];

protected $fillable = [
    'title',
    'version',
];

public function author(){
    return $this->belongsTo(Author::class);
}

public function getAuthorNameAttribute(){
    return $this->author->name;
}

public function getAddressAttribute(){
    return $this->author->address;
}

and in controller use this

return Book::query()->with('author')->first()->makeHidden(['author','author_id']);

Output:

{
  "id": 1,
  "title": "book",
  "version": "v1",
  "created_at": null,
  "updated_at": null,
  "author_name": "komeyl",
  "address": "Iran"
}
like image 36
komeyl-dev Avatar answered Dec 08 '25 21:12

komeyl-dev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!