Good day, I'm trying to get orders with products that have a specific products progress.
My Laravel query looks like this:
return Order::whereHas('products.progress', function (Builder $query) {
$query->where('progress_id', 100)
->orWhereBetween('progress_id', [160, 240]);
})
->with('products.progress')
->select('orders.id', 'orders.customer_id', 'orders.created_at')
->get();
In the query I set a where and whereBetween, the last Product has the progress_id 50 that one should not be loaded into the order.
How to do it? Thank you for reading.
i think you want to Constraining Eager Loads
so your (wheres) should be on the loading ...
return Order::with(['products'=>function($query){
$query->whereHas('progress',function ($query){
$query->where('progress_id', 100)
->orWhereBetween('progress_id', [160, 240]);
})->with('progress');
}])
->select('orders.id', 'orders.customer_id', 'orders.created_at')
->get();
Related
Ok.
I have three tables
products
--product_id
--product_name
--product_type_id
--price15
--price23
--description
--bonus_points
--image
productTypes
--product_type_id
--product_type_name
productQuantities
--id
--product_id
--warehouse_id
--quantity
Products are placed in different warehouses so I have to keep tracks of its numbers
And has relationships are like this
class Product extends Model
{
public function productType() {
return $this->belongsTo('App\Models\ProductType','product_type_id','product_type_id');
}
public function productQuantities() {
return $this->hasMany('App\Models\ProductQuantity','product_id','product_id');
}
}
What I want to get is all columns from products and product type name from productType, sum of quantity from productQuantities, so I can perform search on those column values later on with where().
How can I get these columns with Eloquent?
I know I could get them with raw SQL commands but I need to do this way for compatibility reasons.
I tried this way before I ask the question.
But model relations just stopped working with no errors. Values just got emptied out from the other parts of the page.
$products = Product::selectRaw('products.*, productTypes.product_type_name, sum(product_quantities.quantity) as quantitySum')
->leftjoin('productTypes','products.product_type_id','=','productTypes.product_type_id')
->leftjoin('productQuantities','products.product_id','=','productQuantities.product_id')
->where('products.product_id','like','%'.$searchID.'%')
->where('product_name', 'like', '%'.$searchName.'%')
->where('product_type_name', 'like', '%'.$searchType.'%')
->where(function($q) use ($searchPrice) {
$q->where('price15','like','%'.$searchPrice.'%')
->orwhere('price23','like','%'.$searchPrice.'%');
})
->where('points', 'like', '%'.$searchPoints.'%')
->groupBy('products.product_id')
->orderByRaw($query)
->paginate($paginateBy);
Working version before this was simple.
Product::leftjoin('productTypes','products.product_type_id','=','productTypes.product_type_id')
->select('products.*','productTypes.product_type_name')
->where('products.product_id','like','%'.$searchID.'%')
->where('product_name', 'like', '%'.$searchName.'%')
->where('product_type_name', 'like', '%'.$searchType.'%')
->where(function($q) use ($searchPrice) {
$q->where('price15','like','%'.$searchPrice.'%')
->orwhere('price23','like','%'.$searchPrice.'%');
})
->where('points', 'like', '%'.$searchPoints.'%')
->orderByRaw($query)
->paginate($paginateBy);
And I thought any kind of join methods doesn't seem to be working well with Eloquent relationship? But older one has leftjoin method as well.
I have not tested this (and am assuming you want to group on product_type_name but you should be able to do something along the lines of:
$results = Product::with(['productType','productQuantities'])
->select(DB::raw('products.*,
productType.product_type_name,
sum(productQuantities.quantity) as "QuantitySum"'))
->groupBy('productType.product_type_name')
->get();
OR
$results = DB::table('products')
->join('productType', 'productType.product_type_id', '=', 'products.product_type_id')
->join('productQuantities', 'productQuantities.product_id', '=', 'products.product_id')
->select(DB::raw('products.*,
productType.product_type_name,
productType.product_type_name,
sum(productQuantities.quantity) as "QuantitySum"'))
->groupBy('productType.product_type_name')
->get();
Then you should be able to access the aggregated quantities using (in a loop if you wanted) $results->QuantitySum.
you can get it with eager loading and aggregating. For example, you need to query products has product type name like "new product" and quantity greater than 1000:
Product::with("productType")
->whereHas("productType", function ($query) {
$query->where("product_type_name", "like", "new product");
})
->withCount(["productQuantities as quantity_count" => function ($query) {
$query->selectRaw("sum(quantity)");
}])
->having("quantity_count", ">", 1000)
->get();
you can get through relationship
$product->productType->product_type_name
and attribute:
$product->quantity_count
$products = Product::withsum('productQuantities','quantity')
->leftjoin('product_types','products.product_type_id','=','product_types.product_type_id')
Gives me the result that I wanted. And didn't break the other parts.
But I'm still confused why with() and withSum() didn't work together.
Is it because products belongs to productTypes maybe
I've been create JOIN with eager load with these tables
Transactions (parent of transaction_details)
Transaction_details (child of Transaction and parent of Mutasi_logs )
Mutasi_logs (child of transaction_details)
then i add some filters such as :
only show my data (data that has been created by the user logged in)
only show my saldo
only show my amount
I've try with this code
blahlblah.....
->where('created_by',Auth::id())
->orWhere('amount','LIKE','%'.$search.'%')
->orWhere('saldo','LIKE','%'.$search.'%')
but here where condition not working well (show another user's data like my saldo and amount ) when fill the search field.
here is the output :
and here my full code :
MutasiLog::with([
'transaction_detail.transaction',
])
->orWhereHas('transaction_detail', function (&$q) use ($search) {
$q->where('id', 'like', '%' . $search . '%');
$q->orWhereHas('transaction',function($q) use ($search){
$q->where('description','LIKE','%'.$search.'%');
});
})
->where('created_by',Auth::id())
->orWhere('amount','LIKE','%'.$search.'%')
->orWhere('saldo','LIKE','%'.$search.'%')
->offset($start)
->limit($limit)
->orderBy($order,$dir)
->get();
From the docs "You should always group orWhere calls in order to avoid unexpected behavior when global scopes are applied.". You can find an example there.
So you can do something like this:
// blahlblah.....
->where(function ($query) use ($search) {
$query->where('created_by',Auth::id())
->orWhere('amount','LIKE','%'.$search.'%')
->orWhere('saldo','LIKE','%'.$search.'%');
})
// ...
Or maybe this, depends on your needs:
// blahlblah.....
->where('created_by',Auth::id())
->where(function ($query) use ($search) {
$query->where('amount','LIKE','%'.$search.'%')
->orWhere('saldo','LIKE','%'.$search.'%');
})
// ...
when using orWhere and chained with other wheres, you mean : get data where created_by me or where amount like search , this is why get all data ,so the solution you should group search orWhere on single where like this :
->where('created_by',Auth::id())
->where(function($query){
$query->orWhere('amount','LIKE','%'.$search.'%')->orWhere('saldo','LIKE','%'.$search.'%')
})
I want to filter my query and return only if the user hasRole "Premium" and limit the result to 10.
Along with this query is a count of records which Conversion has and sort it in DESC order by total column.
Right now I have a working query that returns the count of Conversion and with a User but without user filter Role.
// Model Conversion belongs to User
// $from & $end uses Carbon::createDate()
// Current code
$query = Conversion::select('user_id',DB::raw('COUNT(*) as total'))
->whereBetween('created_at', [$from,$end])
->where('type','code')
->where('action','generate')
->whereNotNull('parent_id')
->with('user')
->groupBy('user_id')
->orderBy('total', 'DESC')
->take(10)
->get();
// current result
foreach ($query as $q) {
$q->user->name; // To access user's name
$q->total; // To access total count
}
// I tried this but no luck
$query = Conversion::select('user_id',DB::raw('COUNT(*) as total'))
->whereBetween('created_at', [$from,$end])
->where('type','code')
->where('action','generate')
->whereNotNull('parent_id')
->with('user', function($q) {
$q->hasRole('Premium');
})
->groupBy('user_id')
->orderBy('total', 'DESC')
->take(10)
->get();
You need to use whereHas instead of with, like this:
->whereHas('user', function ($query) {
$query->where('role','Premium');
})
Use the whereHas() instead of with(). Also, you can't use hasRole() if it's not a local scope:
->whereHas('user.roles', function($q) {
$q->where('name', 'Premium');
})
I have two model User and Profile in one to one relationship.
I want to retrieve all user where profile.status == TRUE using following code.
$users = User::with(['profile' => function ($query) {
$query->where('status', TRUE);
}])->get();
dd(count($users)); //50
I have 50 users and only among of them only 3 has status == TRUE. But always it display 50.
You are getting 50 users because you are applying condition to profile. dd($user->profile) you will get only the records of the profile whose status is true.
Use whereHas():
$users = User::whereHas('profile', function ($query) {
$query->where('status', TRUE);
})->get();
dd(count($users));
If you want to make it work with single Query, you can use Query Builder join like
\DB::table('users')->join('profile', function ($join){
$join->on('users.id', '=', 'profile.user_id')->where('profile.status', '=',TRUE);
})->get();
You said you're having N+1 problem, so you need to use both whereHas() and with() like this to get users with profiles and to solve N+1 problem:
$users = User::whereHas('profile', function ($query) {
$query->where('status', TRUE);
})
->with('profile')
->get();
I have many projects and each has many orders, some completed, some not.
I want to order them by the amount of completed orders like this:
$products = $products->orderBy(function($product) {
return $product->orders->where('status', 2)->count();
})->paginate(15);
I know the order call doesn't work like this but this is the best was show the problem. SortBy doesn't work because I want to use pagination.
Finally found a good solution for the problem:
$products = $products->join('orders', function ($join) {
$join->on('orders.product_id', '=', 'products.id')
->where('orders.status', '=', 2);
})
->groupBy('products.id')
->orderBy('count', $order)
->select((['products.*', DB::raw('COUNT(orders.product_id) as count')]))->paginate(50);
Try this if it works:
$categories = Prodcuts::with(array('orders' => function($query) {
$query->select(DB::raw('SELECT * count(status) WHERE status = 2 as count'))
$query->orderBy('MAX(count)')
}))->paginate(15);
return View::make('products.index', compact('categories'));
Note: This is not tested.
From 5.2 on wards you can use the withCount for counting relationship result.
In this case the
$products = $products->withCount(['orders' => function ($query) {
$query->where('status', 2);
}]);
Reference : https://laravel.com/docs/5.2/eloquent-relationships