M@rty's avatar
Level 1

How to exclude the relation column from the collection result array- eager loading

I'm trying to figure out how to exclude/hide the relationship column in the eager load collection result array

I have 2 models and here are the relations

Product.php

class Product extends Model
	{
		public function Category()
		{
			return $this->belongsTo(Category::class);
		}
	}

Category.php

class Category extends Model
	{
		public function Product()
		{
			return $this->hasMany(Product::class);
		}
	}

Table fields

Category: id, name

Product: id, name, category_id

so, here is my query

$result = Product::leftJoin('product_tags', 'product.id', 'product_tags.product_id')
        ->with(['category' => function ($q) {
            $q->selectRaw('id,name as category_name');
        }])
        ->select('product.id', 'product.name','product.category_id',DB::raw('group_concat(DISTINCT(product_tags.product_tag)) as product_tag'))
        ->groupBy('product_tags.product_id')
        ->paginate($limit)
        ->toArray();

here is the response

{
    "id": 50,
    "name": "three",
    "category_id": 2, // this field I need to exclude from result array
    "product_tag": "123,3",
    "category": {
        "id": 2,
        "category_name": "Azo"
    }
}

But I'm expecting the below response

{
    "id": 50,
    "name": "three",
    "product_tag": "123,3",
    "category": {
        "id": 2,
        "category_name": "Azo"
    }
}

I've tried doing it like so:

$result['data'] = collect($result['data'])->except(['category_id']);
$result['data'] = collect($result)->transform(function($i) {
        unset($i->category_id);
			return $i;
    });

even I tried to use the except() helper function but seems all the efforts are meaningless

NOTE: I'm aware I can set protected properties in the model ($hidden or $visible), I might want to use it in different contexts. I want to use the default pagination of laravel.

Is it possible and any way of doing this?

Many thanks.

0 likes
10 replies
M@rty's avatar
Level 1

I'm rather new to laravel could you please set me an example then it would be great, It looks like I'm not aware of these eloquent-resources concept

SilenceBringer's avatar
Level 55

@m@rty as axample

create new resource

php artisan make:resource ProductCollection

get products

$result = Product::with(['tags', 'category' => function ($q) {
            $q->selectRaw('id,name as category_name');
        }])
        ->paginate($limit);

then instead of returning result

return response()->json($result); // or whatever you do

return collection

return new ProductCollection($result);

and in ProductCollection you can modify data

	public function toArray($request)
    {
        return $this->collection->map(function ($product) {
				return [
						'id' => $product->id,
						'name' => $product->name,
						'product_tag' => $product->tags->pluck('id')->implode(','), // assuming you have `tags` relation. or can replace it with the way you did it before
						'category' => [
								'id' => $product->category->id,
								'name' => $product->category->name,
						],
				];
		})->toArray();
    }

your response will contains data with the result of toArray method of collection + meta with the links from pagination (will be added automatically)

just as example. Adapt it to your case

1 like
M@rty's avatar
Level 1

Thank you so much, I really appreciate your example

eloquent-resources is really very helpful and got a chance to aware of this new concept, I had tried so hard for the day for getting the solution.

you are my Savior! :)

M@rty's avatar
Level 1

Hey, is it best practice if I want to return a proper JSON response with a collection?

$list = $this->collection->map(function ($product) {
            return [
                    'id' => $product->id,
                    'name' => $product->name,
                    'product_tag' => $product->ProductTag->pluck('product_tag')->implode(','),
                    'category' => $product->category,
            ];
        })->toArray();

        return [
            'status' => true,
            'message' => 'Success',
            'rows' => $list
        ]; 

//Result:

"data": {
        "status": true,
        "message": "Success",
        "rows": [
			{
                "id": 50,
                "name": "three",
                "product_tag": "123,3",
                "category": {
                    "id": 2,
                    "category_name": "Azo"
                }
            },
			{...}
		]
	}
SilenceBringer's avatar

@m@rty no. values like status and message should be at the top level, not inside data

Please or to participate in this conversation.