In Laravel my table columns overwrite with join, how can i solve? - php

I have a mini problem in my application... I want to get all products from the products table along with the category name from the categories table and get stock of each product from products_attribute table... the problem is product table id overwrite with products_attribute id. In the product_attributes table, only 116 rows but products table has 177 rows and the loop gets only 116 rows with products_attribute id.
Product Table (Screenshot)
Product Attributes Table (Screenshot)
Categories Table (Screenshot)
public function viewProducts(Request $request)
{
$products = Product::join('categories', 'categories.id', 'products.category_id')->join('products_attributes', 'products_attributes.product_id', 'products.id')->get();
$products = json_decode(json_encode($products));
return view('admin.products.view_products')->with(compact('products'));
}

Laravels join function default is inner join so You will need to use the leftJoin method. (See \vendor\laravel\framework\src\Illuminate\Database\Query\Builder#join)

I hope It will be helpful.. How to use left join:
$products = Product::join('categories', 'categories.id', 'products.category_id')->leftjoin('products_attributes', 'products_attributes.product_id', 'products.id')->get();

You have to use aliases to preserve columns from the base table that will be overwritten by your joining table(s):
$products = Product::select('*', \DB::raw("product.id as product_id"))->join('categories', 'categories.id', '=', 'product.id')->get();
You can then access the product id using: $product->product_id

Related

Not able to fetch data from primary table in laravel

I have 3 tables i.e category, sub category and products. I have passed category id to sub category and then sub category id to product so that i can get the whole data as per requirements. The problem in i an able to get the data from the secondary tables that has joins statement not from the primary table.Here is my code of query. Any help from you would be appreciated
public function showProduct()
{
$data = DB::table('category')
->join('sub_category','category.id',"=",'sub_category.category_id')
->join('product','sub_category.id', '=', 'product.sub_category_id')
->get();
return $this->success('date' ,$data);
}
use leftjoin
$data = DB::table('category')
->leftjoin('sub_category','category.id',"=",'sub_category.category_id')
->leftjoin('product','sub_category.id', '=', 'product.sub_category_id')
->get();

How get most product added to favorites list in laravel?

I have favourites table like this:
id -user_id - product_id
It's for user to add the favourites product, and I have my relation in User Model:
public function favourites()
{
return $this->belongsToMany(Product::class ,'favourites')->withTimestamps();
}
How can I fetch the most product added to favorites by users! ?
You can use count(*) with group by.
Favorite::selectRaw('product_id, count(product_id) as times_added')
->groupBy('product_id')
->orderByDesc('times_added')
// ->limit(5) if you want to get the top 5
->get();
If you don't have a model for your favorites table you can use the DB facade.
DB::table('favorites')
->selectRaw('product_id, count(product_id) as times_added')
->groupBy('product_id')
->orderByDesc('times_added')
// ->limit(5) if you want to get the top 5
->get();

Laravel join two tables for ruled out records

In Laravel, how can I reject a record in a query based on a value with one of the table with which this table has relations?
For example, I have the Products table and the Categories table. The Categories table has a one-to-many relationship, one category can have many products. The categories table are is_visible is_deleted. How to make inquiries on the Products table so that it rejects products that belong to the category that has and set fields is_visible = false or is_deleted = true ?
I tried something like this:
$products = ProductTable::join('product_category_tables', 'product_category_tables.id', '=', 'product_tables.id')
->where('product_category_tables.is_visible', '=', true)
->where('product_category_tables.is_deleted', '=', false)
->where('product_tables.is_visible', '=', true)
->where('product_tables.is_deleted', '=', false)
->paginate(50);
But from this query I have only one record. I can't make this query on Category table becouse I want get only 25/50/100 products for paginate.
If you are using Laravel Modal(Eloquent) and have defined the one to many relationship properly in both Product and Category Model. then you can achieve this by the following query:
$products = Product::where("is_visible", true)
->where("is_deleted", false)
->whereHas('category', function($categories){
$categories->where("is_visible", true)
->where("is_deleted", false);
})
->get();
In Product model you should have defined the relationship as bellow:
public function category()
{
//From your mentioned query I am seeing that
//product table's id is actually categories table's id(which should not be like this though),
//so the relationship is
return $this->belongsTo(Category::class, 'id');
}

Laravel Group By relationship column

I have Invoice_Detail model which handles all products and it's quantities, this model table invoice_details has item_id and qty columns.
The Invoice_Detail has a relation to Items model which holds all item's data there in its items table, which has item_id, name, category_id.
The Item model also has a relation to Category model which has all categories data in its categories table.
Question: I want to select top five categories from Invoice_Detail, how?
Here's what I did:
$topCategories = InvoiceDetail::selectRaw('SUM(qty) as qty')
->with(['item.category' => function($query){
$query->groupBy('id');
}])
->orderBy('qty', 'DESC')
->take(5)->get();
But didn't work !!
[{"qty":"11043","item":null}]
Category::select('categories.*',\DB::raw('sum("invoice_details"."qty") as "qty"'))
->leftJoin('items', 'items.category_id', '=', 'categories.id')
->leftJoin('invoice_details', 'invoice_details.item_id', '=', 'items.id')
->groupBy('categories.id')
->orderBy('qty','DESC')
->limit(5)
->get();
This will return you collection of top categories.
Tested on laravel 5.5 and PostgreSQL.
UPD:
To solve this without joins you can add to Categories model this:
public function invoiceDetails()
{
return $this->hasManyThrough(Invoice_Detail::class, Item::class);
}
And to select top 5 categories:
$top = Category::select()->with('invoiceDetails')
->get()->sortByDesc(function($item){
$item->invoiceDetails->sum('qty');
})->top(5);
But first solution with joins will work faster.

Inner join single column using Eloquent

I am trying to get a single column of an inner joined model.
$items = Item::with('brand')->get();
This gives me the whole brand object as well, but I only want brand.brand_name
$items = Item::with('brand.brand_name')->get();
DidnĀ“t work for me.
How can I achieve this?
This will get related models (another query) with just the column you want (an id, see below):
$items = Item::with(['brand' => function ($q) {
$q->select('id','brand_name'); // id is required always to match relations
// it it was hasMany/hasOne also parent_id would be required
}])->get();
// return collection of Item models and related Brand models.
// You can call $item->brand->brand_name on each model
On the other hand you can simply join what you need:
$items = Item::join('brands', 'brands.id', '=', 'items.brand_id')
->get(['items.*','brands.brand_name']);
// returns collection of Item models, each having $item->brand_name property added.
I'm guessing Item belongsTo Brand, table names are items and brands. If not, edit those values accordingly.
Try this:
$items = Item::with(array('brand'=>function($query){
$query->select('name');
}))->get();

Categories