6

I am trying to get a collection of categories only if they are in the products table. My categories table has 300 items. I only want a collection if a category is attached in the products table. The $categories collection should only result in about 10 categories because there are only about 10 products that have different category_ids

$products = DB::table('products')->groupBy('category_id')->get();

foreach($products as $product){
        $categories[] = DB::table('categories')->where('id', '=', $product->category_id)->first();
}

$categories = collect($categories)->all();

Maybe I am going about this wrong and should use a different query builder method?

The end result $categories does get the results I am after but in my blade I get the "Trying to get property of non-object" error.

1
  • Please see my edit. This can be done with 3 lines of the query builder. Commented May 24, 2019 at 16:39

3 Answers 3

6

If using $categories in your blade file as a collection, you will need to remove the ->all() method.

->all() is converting the collection into an array after it is being created:

$categories = collect($categories);
Sign up to request clarification or add additional context in comments.

1 Comment

Yup, it's that simple. I needed countable back!
2

You get Trying to get property of non-object because one of

DB::table('categories')->where('id', '=', $product->category_id)->first();

return null value.
You can fix it this way

$products = DB::table('products')->groupBy('category_id')->get();

$categories = collect();
foreach($products as $product){
    $category = DB::table('categories')->where('id', '=', $product->category_id)->first();
    if ($category) {
        $categories->push($category); 
    }
}

If you want to get collection instance you must be use collect() helper method with array argument. For example

collect($categories); // is_array(categories) is true

You are doing many request in foreach. That is not right way. Instead it you can achieve collection instance doing only 2 request.

 $categoryIds = DB::table('products')->pluck('category_id')->toArray();
 $categories = DB::table('categories')->whereIn('id', $categoryIds)->get();

See docs https://laravel.com/docs/5.8/queries#retrieving-results

3 Comments

Code dump, no text no explanation? With 4K rep I'd think you would know to add something.
@AbraCadaver Edit answer with explanation. If you want you can improve it. but this is solution with 2 quesries
This did the trick. Thanks. I would agree however that doing it through a relationship would be a better use of code
1

This can be done with one simple eloquent query. There's no need to use query builder unless you're doing something overly complex (in my opinion).

whereHas() will only return Categories that have Products.

Categories::with('products')->whereHas('products')->get();

As long as the relationships are correct on the models the above is what you're looking for. As pointed out in the comments, you need models and relationships. Laravel uses the MVC pattern, and the first letter stands for model so I'm going to guess you're using them. If not let me know and I can help set those up because you should be using them.

And if you NEED to use the query builder clean that code up and use something like this so you don't have to worry about recollecting. Also check out the hydrate() method to change these generic class instances into instances of the Categories model.

DB::table('categories')->whereIn('id', function($q){
    $q->select('category_id')->from('products');
})->get();

1 Comment

This may require the creation of the relationships and models so would be good to explain in your answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.