Laravel Where Count > N - laravel

I have 2 models in my app:
1. Customer.php
2. Car.php
Now I would like to run a query that returns all customers that have less than 2 cars. Where 2 is a number that can be changed by the user.
I have tried this but it didn't work, it just returns all customer records:
$customers = Customer::whereHas("cars", function($query) {
$query->selectRaw("count(*) < ?", [2]);
})
->get();
Edit:
The two models are linked in a pivot table, meaning A customer can have more than 1 car and a Car can belong to more than 1 customer.

Use this:
$customers = Customer::withCount('cars')
->having('cars_count', '<', 2)
->get();

So , here is the result.
Relation in model Customer.php
public function cars()
{
return $this->belongsToMany('App\Car','car_customer','car_id','customer_id');
}
Query to get all customers with N cars:
$userInput = 2;
$data = Customer::with('cars')
->withCount('cars')
->has('cars', '<', $userInput)
->orderBy('cars_count', 'desc')
->get();
Where the $userInput is your 'N'.

This is the best way:
$customers = Customer::has('cars','<', 2)->get();

Have you tried this approach?
$input = 2;
$customers = Customer::whereHas("cars", function($query) use ($input) {
$query->where(DB::raw("count(cars.id)"), "<", DB::raw($input))
})->get();

Related

How to add a momentary value to a sql query in Laravel

I have this query in Laravel 8:
$articles = Article::whereIn('category_id', $categories)->where(function ($query) {
$query->where(function ($query2) {
$query2->where('draft', 0)->whereNull('publication_date');
})->orWhere(function ($query2) {
$query2->where('draft', 0)->where('publication_date', '<=', DateHelper::currentDateTime());
});
})->orderBy('publicated_at', 'DESC')->get();
I need to add a momentary id to this query named desc_id, so that the values $articles that i query have a desc_id based on the publication_date.
The result that i need to achieve is like this:
id
name
category
publication_date
desc_id
3
bananas
news
2022-01-16 17:30:00
1
27
kiwis
news
2021-12-05 21:30:00
3
50
apples
news
2022-01-07 09:14:00
2
I've tried adding it by passing all the elements of $articles into an empty array adding a value:
$count =0;
$allArticles = [];
foreach ($articles as $article) {
$count++;
$allArticles[] = $article->with('desc_id', $count);
}
I know that my method is incorrect but i hope that it helps understanding my question.
It looks like you want to have the line number of each row which can be achieve like this :
Article::whereIn(...)->select()
->addSelect(DB::raw('RANK() OVER(ORDER BY publicated_at DESC) as desc_id'))
->orderBy('publicated_at', 'DESC')
->get();

Laravel whereHas Returns all records

I have have 3 tables in my projects they are:
products(can have Multiple Variants)
variants (belongsto product)
product_attributes (this have product_id,attribute_id,value_id)
I want to filter variants from a product by value ids thats comes from form request as example (1,2,6)
I have tried like this:
$poruduct_id = $request->product_id;
$value_ids = $request->value_ids;
$searched_variants = Variant::whereHas('product.attributeValues', function ($query) use ($value_ids, $product_id) {
$query->whereIn('value_id', [$value_ids]);
})->where('product_id', $product_id)->get();
dd($searched_variants);
But the problem is the query returns all records from the product. What is the solution to filter exactly the values that the product Variants have?
Thank you.
-UPDATED-
I have tried like this but nothing changed
$searched_variants = Variant::select('product_id')->whereHas('product.attributeValues', function ($query) use ($value_ids, $product_id) {
$query->whereIn('value_id', [$value_ids]);
})->groupBy('product_id')
->havingRaw('COUNT(*) = ?', [count((array) $value_ids)])
->get();
-**FİNALLY SOLUTİON**-
I made it like this : I get the value code that is in for example Large the code is L
get all the codes to controller and executed this query ı hope this helps someone
1.$value_codes=$request->value_codes;
2.$value_codes_array=explode(',',$value_codes);
3.$product_id=$request->product_id;
4.$searchValues = preg_split('/,/', $value_codes_array, -1, PREG_SPLIT_NO_EMPTY);
$searchValues = preg_split('/,/', $value_idss, -1, PREG_SPLIT_NO_EMPTY);
$variants= Variant::where(function ($q) use ($searchValues) {
foreach ($searchValues as $value) {
$q->orWhere('sku', 'like', "%-{$value}")
->orWhere('sku', 'like', "%-{$value}-%")
->orWhere('sku', 'like', "{$value}-%");
}
})->where('product_id',$product_id)->get();
dd($variants);
If you have n variants to one product, you query should be like:
Product Model
public function variants: HasMany relationships
//usage
$produtc->variants->and here the query function
You need to use it in this way, it should work:
$productId = $request->product_id;
$valueIds = $request->value_ids;
$searchedVariants = Variant::whereHas('product.attributeValues', function ($query) use ($valueIds) {
$query->distinct()->whereIn('value_id', $valueIds);
}, '=', count($valueIds))->where('product_id', $productId)->get();

check count in one to many relation in laravel

I have products table that each of the product has many orders,product.php
public function orders()
{
return $this->hasMany(Order::class,'product_id');
}
I can get products that order by order_count with this code:
$products = Product::withCount('orders')->orderBy('orders_count', 'desc')->get();
Now I want to get products in controller that their orders count is bigger than 5,
How I can do it?
One way to do this would to use whereHas():
$products = Product::withCount('orders')
->whereHas('orders', null, '>', 5)
->orderBy('orders_count', 'desc')
->get();
I don't think it's mentioned in the docs but you don't have to pass a closure as the 2nd param, and the 3rd and 4th can be used to pass the operator and the count.
Alternatively, you could use having() instead:
$products = Product::withCount('orders')
->having('orders_count', '>', 5)
->orderBy('orders_count', 'desc')
->get();
You can use mapping on your collection to filter out records e.g. :`
$collection = collect($products)->map(function ($product) {
return $product->orders->count() > 5;
})
->reject(function ($name) {
return $product->orders->count() < 5;
});`
This is just an example, you can put more conditions if required.
Hope this helps.
The below code should give you just the orders with a count greater than 5
$products = Product::withCount('orders')->where('orders_count', '>', 5)->orderBy('orders_count', 'desc')->get();
Adding ->where() should do it.
Hope that helps.
Update
Try
->whereRaw('count("orders.id") > 5')
This should work to get products with more than 5 orders.

How to sorting by current login user first in Laravel?

Below code is to divide list view by permission in the Job table.
public function index(Request $request)
{
$user_name = Auth::user()->name;
$jobs = Job::orderBy('created_at', 'desc') //#default
->where('is_trash', '==', 0)
->paginate(15);
if(!Auth::user()->hasPermissionTo('Admin')){ //check by permission
$jobs = Job::orderBy('created_at', 'desc')
->where('user_name', '=', $user_name)
->where('is_trash', '==', 0)
->orderby('updated_at', 'desc')
->orderBy('deleted_at', 'desc')
->paginate(15);
}
return view('jobs.index')
->with('jobs', $jobs);
}
For example, current login user name is C and there has A, B, D users.
Then I wish to show list as
------------------------------
C
A
B
D
------------------------------
How do I sort the currently logged in users first in the list?
Thank you in advance.:)
To place a row above all other rows and then order the remaining rows in ascending / descending order you need to do something like this SELECT * FROM table ORDER BY field = value ASC
So for your query something like this should work
$user_name = Auth::user()->name;
$jobs = Job::orderByRaw("user_name = ':name' ASC", ['name' => $user_name])
->orderBy('created_at', 'desc')
->where('is_trash', '==', 0)
->paginate(15);
I'm not entirely sure which query you wish to order and by which field but this example should give you enough to adapt on. It is untested but if :name isn't working as per the example try wrapping the query in \DB::raw() to add the binding $user_name.
You could use collections for that. Just tested, works perfectly:
list($user, $collection) = $collection->partition(function($user) {
return $user->id === auth()->id();
});
$collection = $user->merge($collection);

Laravel: join Eloquent models

Question. How can I use Eloquent to produce this query:
SELECT campaigns.name, users.name FROM campaigns LEFT JOIN users on campaigns.gamemaster_id = users.id where campaigns.status = 1
Campaigns
id gamemaster_id name status
1 1 campaign1 1
2 2 campaign2 1
Users
id name
1 rick
2 bob
Result
id gamemaster_id name status gamemaster_name
1 1 campaign1 1 rick
2 2 campaign2 1 bob
Campaign model
class Campaign extends Model
{
public function gamemaster()
{
return $this->belongsTo('App\User', 'gamemaster_id');
}
}
My try to make Eloquent, but that fails:
$result = Campaign::where('status', '=', 1)->with('gamemaster')->select('name')->orderBy('users.updated_at', 'desc')->get();
You can do it in two ways, first using the query builder,
$campaigns = DB::table('campaigns')->leftJoin('users', 'campaigns.gamemaster_id', '=', 'users.id')
->select(['campaigns.name as name', 'users.name as gamemaster_name'])
->where('campaigns.status', '=', 1)
->orderBy('users.updated_at', 'desc')
->get();
And with eager loading, you can get the campaigns like below. However, to sort by relation property, you need an another layer which is not that easy to implement.
$campaigns = Campaign::where('status', '=', 1)->with(['gamemaster' => function($query){
$query->select(['id', 'name']);
}]->select('id', 'gamemaster_id', 'name')->get();
But you can use collection functions to easily sort it (However, it will take more execution time)
$campaigns = Campaign::where('status', '=', 1)->with(['gamemaster' => function($query){
$query->select(['id', 'gamemaster_id', 'name', 'updated_at']);
}]->select('id', 'name')->get()->sortByDesc(function ($campaign) {
return $campaign->gamemaster->updated_at;
})
The following query should work:
Campaign::whereStatus(1)
->join('users', 'campaigns.gamemaster_id', '=', 'users.id')
->select('campaigns.name', 'users.name')
->orderBy('users.updated_at', 'desc')
->get()

Resources