Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Simbaa's avatar

Get specific columns of relation table

I have 3 tables: categories, subcategories and products. Product table have category_id and subcategory_id as a foreign_key .

I already defined relation in category, subcategory and product Model.

I want to select all products from product table with below conditions:

  • Select some columns from products table - like id, name, discount, price
  • select some columns from category table - e.g. id, name
  • Select some columns from subcategory table - e.g. id, name
$products = Product::with('category:id,name')
->with('subcategory:id,name')
->get()->toArray();

Above code is working fine it is returning custom columns of category and subcategory table as I defined in with method but It also returning all column of product table. Where should I define column of product table?

How should I do this?

0 likes
17 replies
jpmg's avatar

$var = categoy[0]['name'];

jpmg's avatar

@Simbaa Look at this test I did to explain, I hope it helps you.

	$c => [
 			[
   				"id" => 1,
   				"user_id" => 3,
   				"city_id" => 1,
   				"city" => [
     			"id" => 1,
     			"country_id" => 1,
     			"city_name" => "-",
   		],
   "business_categorie" => [
     "id" => 1,
     "business_sector_id" => 1,
     "category_name" => "Pizzeria",
   ],
 ],
 [
   "id" => 2,
   "user_id" => 3,
   "city_id" => 2,
   "business_categorie_id" => 1,
   "name_digitpoint" => "Laarepa",
   "city" => [
     "id" => 2,
     "country_id" => 1,
     "city_name" => "M",
   ],
   "business_categorie" => [
     "id" => 1,
     "business_sector_id" => 1,
     "category_name" => "Pizzeria",
    ],
  ],
]

and to get some data

  1.   $c[0]['city']
       => [
          "id" => 1,
           "country_id" => 1,
          "city_name" => "-",
     ]
    
  2.   $c[0]['city']['id']
        => 1
    
tykus's avatar

Assuming the products table has foreign keys for category_id and subcategory_id (you must include these for eager-loading):

$products = Product::with('category:id,name')
    ->with('subcategory:id,name')
    ->select('id', 'name', 'discount', 'price', 'category_id', 'subcategory_id')
    ->get()
    ->toArray();
2 likes
Simbaa's avatar

@tykus Sir, how should I concatenate image directory path for eg My images are in

asset('storage/products/'. $product->image)

Where should I put path in the below code?

$products = Product::with('category:id,name')
    ->with('subcategory:id,name')
    ->select('id', 'name', 'discount', 'price', 'category_id', 'subcategory_id')
    ->get()
    ->toArray();

or something like below?

public function index () {
$products = Product::with('category:id,name')
    ->with('subcategory:id,name')
    ->select('id', 'name', 'discount', 'price', 'category_id', 'subcategory_id')
    ->through(function($product) {
            return [
                'id'=> $product->id,
                'name' => $product->name,
                'image' =>asset('storage/'. $product->image),
                'category' => $product->category,
                'subcategory' => $product->subcategory,
            ];
        });
    ->toArray();
return Inertia::render('Products/Index', [
        'products' => $products
    ]);
}
kokoshneta's avatar

@Simbaa You shouldn’t put the image code anywhere in that. You should use an accessor to build the correct path so that accessing $product->image will automatically give the path you need.

Also, you’re missing the call to get() (meaning you don’t actually fetch any records), and collections have no through() method, so your code here will fail.

1 like
Simbaa's avatar

@kokoshneta okay, I will fix it by removing ->through method and adding ->get() method before ->toArray()

Can I add paginate after ->select() and before ->get() method?

tykus's avatar

@Simbaa if you don't select the relevant columns neither the original asset('storage/'. $product->image) or suggested accessor method will work - the image column not being in the selected columns. To be honest, I don't know what your mapping operation is doing since the price and discount columns you selected are just being discarded 🤷‍♂️ - do you actually need to paginate the query?

1 like
Simbaa's avatar

@tykus Yes, I want to paginate with selected columns from all 3 table as mentioned above and also want image from specific path’ (as you said earlier - I have to set custom image path using accessor method`)

tykus's avatar
tykus
Best Answer
Level 104

@Simbaa you can add an accessor to the Product model:

public function image(): Attribute
{
    return new Attribute(get: fn ($image) => asset('storage/'. $image));
}

_If you name the accessor method differently, you can add it to the $appends array so it is serialized with the Model.

public function index ()
{
    $products = Product::with('category:id,name')
        ->with('subcategory:id,name')
        ->select('id', 'name', 'image', 'discount', 'price', 'category_id', 'subcategory_id')
        ->paginate();

    return Inertia::render('Products/Index', [
        'products' => $products
    ]);
}

You could also consider creating a Eloquent API Resource to design the structure of the JSON representation of the Product instance.

1 like
kokoshneta's avatar

@Simbaa Yes, if you want to paginate the results, then the call you were missing would be paginate() instead of get(). Since paginators do have a through() method, your through() call would also succeed in that case – apart from the fact that $topic->id will be undefined – where did $topic suddenly come from, and what is it?

Like @tykus, though, I don’t really see why you’re doing all this.

  • Why are you specifying which columns to fetch, only to discard some of them without ever using them?
  • Why are you specifying columns to begin with? What’s the problem with just fetching all of them and using what you need?
1 like
Simbaa's avatar

@kokoshneta Yes, if you want to paginate the results, then the call you were missing would be paginate() instead of get().

Okay

where did $topic suddenly come from, and what is it?

It was typo

Why are you specifying which columns to fetch, only to discard some of them without ever using them?

How? by using makeHidden()??

Why are you specifying columns to begin with? What’s the problem with just fetching all of them and using what you need?

Because I am using VueJs in Frontend and everything will be visible in the props that's why

tykus's avatar

@Simbaa really just make a Resource class for this - messing about with property visibility on the Model class is painful

Simbaa's avatar

@tykus I defined accessor like below but still getting only image name

use Illuminate\Database\Eloquent\Casts\Attribute; //Import also added
protected function image(): Attribute
    {
        return Attribute::make(
            get: fn ($image) => asset('storage/product_images'. $image),
        );
    }

Below is my controller method

public function index()
    {
        $products = Product::with('category:id,name')
                            ->with('subcategory:id,name')
                            ->select(
                                'id', 'name', 'price', 'description', 
                                'discount', 'image','category_id','subcategory_id'
                            )->paginate();
        return Inertia::render('Product/Index', compact('products'));
    }
kokoshneta's avatar

@Simbaa First off, your posts keep switching quotes and replies, which is confusing to read. When you start a line with >, that’s a quote, not a reply.

By specifying columns and then discarding, I meant why do you first do ->select([column names]) in the query, but then also run the results through the ->through() call, where you don’t use the price and discount columns. Why do it twice, with different columns? If you drop the ->select() call, the result will be exactly the same, but more readable.

But it seems @tykus has convinced you to make a resource class, which is good – that’s precisely what resource classes are for. And with a resource class, you don’t need to worry about any of this, because you explicitly define the array that should be returned.

1 like
Simbaa's avatar

@kokoshneta Okay Sir, next time I will also focus on better formatting my answers and sir I am new in Laravel. You and @tykus gave me better approaches to solve the problem. Thank you very much, sir, for giving me your valuable time.

Please or to participate in this conversation.