How to make a condition based on relation ship count in Laravel Eloquent? - laravel

I would like to add a condition based on the tasks relationship count,
Here is the code:
return TeamleaderDeal
::withCount('tasks')
->get();
The result is:
[
{
"id": 4,
(...)
"dealPhase": "Refused",
"tasksCount": 5,
(...)
},
{
"id": 5,
(...)
"tasksCount": 0,
"companyLanguage": "nl",
(...)
},
{
"id": 16,
(...)
"dealPhase": "New",
"tasksCount": 17,
(...)
},
{
(...)
How to only return results where tasksCount equal to 5?

You may use has method like this:
// Retrieve all team-leader deals that have 5 tasks...
return TeamleaderDeal
::has('tasks', '=', 5)
->get();
Check Laravel docs for more info.

Related

How we get specific columns from multiple relations using With() in Laravel

I need some specific columns from two relations.
In my questions model I have two relations
public function ans_options()
{
return $this->hasMany('App\Models\AnswerChoices', 'ac_quest_id', 'q_id');
}
public function question_category()
{
return $this->hasOne("App\Models\Categories", 'cat_id', 'q_category');
}
I tried
Questions::with(array(
'questionCategory' => function($query) {$query->select('cat_id','cat_value');},
'ans_options' => function($query1) {$query1->select('ac_id','ac_choiceTxt');}
))->get();
am getting only the columns of question_category not in ans_options
{
"q_id": 349,
"q_project_id": 140,
"q_text": "<p>Gender</p>",
"question_category": {
"cat_id": 1,
"cat_value": "normal"
},
"ans_options": []
}
But when I try the below code all columns of ans_options are getting.
Questions::with('questionCategory:cat_id,cat_value','ans_options')->get();
like
{
"q_id": 349,
"q_project_id": 140,
"q_text": "<p>Gender</p>",
"question_category": {
"cat_id": 1,
"cat_value": "normal"
},
"ans_options": [
{
"ac_id": 334,
"ac_quest_id": 349,
"ac_choiceTxt": "Male",
"ac_modifiedOn": "2021-11-24T06:22:00.000000Z",
"ac_status": "active"
},
{
"ac_id": 335,
"ac_quest_id": 349,
"ac_choiceTxt": "Female",
"ac_modifiedOn": "2021-11-24T06:22:00.000000Z",
"ac_status": "active"
}
]
}
I need only ac_id and ac_choiceTxt from ans_options. How can I achieve that?
to make Laravel able to load the relation, you should select the foreign key that responsible for that relation
Questions::with(array(
'questionCategory' => function ($query) {
$query->select('cat_id', 'cat_value');
},
'ans_options' => function ($query1) {
$query1->select(
'ac_id',
'ac_choiceTxt',
'ac_quest_id'
);
}
))->get();
just add 'ac_quest_id' to your select.
You can make model where available only this fields
Extend current model from new (with removing columns from curent)
use "with" from new short model
I don't know another way at now...
Then we can add the primary key here also. It will get the same result and then no need of closures here.
Questions::with('questionCategory:cat_id,cat_value',
'ans_options:ac_id,ac_choiceTxt,ac_quest_id')
->get();

Laravel - How to combine multiple queries as one Eloquent Query

In my Laravel-5.8, I have these four queries accessng the same model:
$allLeaves = HrLeaveRequest::where('company_id', $userCompany)->whereYear('created_at', date('Y'))->count();
$pendingLeaves = HrLeaveRequest::where('leave_status', 1)->where('company_id', $userCompany)->whereYear('created_at', date('Y'))->count();
$rejectedLeaves = HrLeaveRequest::where('leave_status', 3)->where('company_id', $userCompany)->whereYear('created_at', date('Y'))->count();
$approvedLeaves = HrLeaveRequest::where('leave_status', 4)->where('company_id', $userCompany)->whereYear('created_at', date('Y'))->count();
How do I combine the four queries as one
something similar to this
$gender_unpublished_record = HrEmployee::selectRaw('count(gender_code) as count,gender_code, if (gender_code = 1, "Male", "Female") as gender')->whereNotIn('employee_code', $publishedgoals)->where('company_id', $userCompany)->where('hr_status', 0)->groupBy('gender_code')->get();
The one above only have 0 or 1. But what I want to achive takes care of everything in the table, leave_status as 1, 3 and 4
Thank you
in your Company Model you should have the relation:
public function HrLeaveRequests()
{
return $this->hasMany(HrLeaveRequest::class,'company_id');
}
now you could use withCount:
$value=Company::where('company_id',$userCompany)->withCount(['HrLeaveRequests as allLeaves'=>function($query){
$query ->whereYear('created_at', date('Y'));
},
'HrLeaveRequests as pendingLeaves'=>function($query){
$query->where('leave_status', 1)->whereYear('created_at', date('Y'));
},
'HrLeaveRequests as rejectedLeaves'=>function($query){
$query->where('leave_status', 3)->whereYear('created_at', date('Y'));
},
'HrLeaveRequests as approvedLeaves'=>function($query){
$query->where('leave_status', 4)->whereYear('created_at', date('Y'));
},
])->get();

Laravel collection nested group by get different field count

There is data as below.
"2017-08-13": [
{
"cancelledByDriver": 0,
"busy": 0,
"cancelledByRider": 0,
"acceptedByDriver": 1,
"requestDate": "2017-08-12T21:03:29.754Z"
},
{
"cancelledByDriver": 0,
"busy": 0,
"cancelledByRider": 0,
"acceptedByDriver": 1,
"requestDate": "2017-08-12T21:08:28.244Z"
}
],
"2017-08-14": [],
"2017-08-15": [],
"2017-08-18": [],
"2017-08-20": [],
"2017-08-21": [],
"2017-08-22": [],
"2017-08-23": [],
"2017-08-24": [],
"2017-08-25": []
I want to print the number of values in fields 1 in each date.So in a date how many cancelledByDriver, busy, canceledByRider and acceptedByDriver (value = 1).
Example:
"2017-08-13": [
{
"cancelledByDriver": 0,
"busy": 0,
"cancelledByRider": 0,
"acceptedByDriver": 2,
}
]
My Code:
$days = $tripRequests->groupBy(function($item) {
return date('Y-m-d', strtotime($item['requestDate']));
})->map(function ($item, $key) {
return collect($item);
});
I'm not sure if you solved the question or not. But I have same question about this. Finally I found answer according to Laravel's Collection guides.
$days = $tripRequests->groupBy(function($item) {
return date('Y-m-d', strtotime($item['requestDate']));
})->map(function ($item) {
return $item->sum('cancelledByDriver') ;
});
First, the method groupBy() is able to group a collection by given keys, that's what you are correctly doing. Then with the method map() allows you to re-mapping the collection objects by walking through the each items which associated with date, such as 2017-08-13. What you need to do is call sum() in order to sum the cancelledByDriver up.
You will get a new collection with the sum of cancelledByDriver which group by-ed by the date.
https://laravel.com/docs/5.6/collections#method-sum

Change Laravel Relationship Output Structure

I'm using Laravel 5.2 and I have Role and Permission models with
Role.php
public function permissions()
{
return $this->hasMany('App\Permissions');
}
And if I call
return Role::with('permissions')->get()
it will return
[{
"id": 2,
"name": "training_vendor",
"display_name": "Training Vendor",
"description": "Role for vendor",
"created_at": "2016-06-23 08:05:47",
"updated_at": "2016-06-23 08:05:47",
"permissions": [
{
"permission_id": 1,
"role_id": 2
},
{
"permission_id": 2,
"role_id": 2
},
{
"permission_id": 3,
"role_id": 2
},
{
"permission_id": 4,
"role_id": 2
},
{
"permission_id": 5,
"role_id": 2
}
}]
Is it possible to change the "permissions" structure to something like these?
[{
"id": 2,
"name": "training_vendor",
"display_name": "Training Vendor",
"description": "Role for vendor",
"created_at": "2016-06-23 08:05:47",
"updated_at": "2016-06-23 08:05:47",
"permissions": [1,2,3,4,5]
}]
If you want to get an array (as title says), use toArray() method:
return Role::with('permissions')->get()->toArray();
It will convert the collection to an array.
If you need to get custom formatted JSON (as your example shows), use toArray(), then rebuild this array with using foreach or array_map()/array_filter() methods and encode result into JSON with json_encode().
I would recommend you to send data as is (without rebuilding it's structure) to frontend or whatever and work with it there.
I order to extract a Collection of permission IDs you can use the pluck() function:
$permissionIds = $role->permissions->pluck('permission_id');
You can also write a getter function in your Role model:
public function getPermissionIds()
{
return $this->permissions->pluck('permission_id');
}
and use it like:
$permissionIds = $role->getPermissionIds();
You can even override the magic __get() function:
public function __get($attr)
{
if ($attr === 'permissionIds') {
return $this->getPermissionIds();
} else {
return parent::__get($attr);
}
}
and access the permission IDs like an attribute:
$permissionIds = $role->permissionIds;
In Laravel 5.2 the returned value of models is a Collection instance which can be used to transform the result
$roles = Role::with('permissions')->get();
$roles->transform(function($role){
$role['permissions'] = $role['permissions']->pluck('permission_id')->toArray();
return $role;
});
return $roles;
This code will provide the desirable result.
Note: You can even chain the transform function after the get function.
I hope this answer will help to you,
$role = Role::all();
foreach ($role as $index){
$permissions= $index->permissions;
foreach ($permissions as $permission){
$permissionId[] = $permission->permission_id;
}
unset($index->permissions);
$index['all_permissions']= $permissionId;
}
return response()->json($role, 200);
This is work for me. So check for your code.

Eloquent sort by relationship column

I'm kind of lost, i'm trying to count the distance and sort mission closest to the logged in user. The problem is that my lat and lng is in another table (Buildings), which is defined as a relation in Mission.
I'm using Laravel/Lumen's QueryBuilder to fetch records from the database.
$orderBy = "DEGREES(ACOS(COS(RADIANS($lat)) * COS(RADIANS(lat)) * COS(RADIANS($lng) - RADIANS(lng)) + SIN(RADIANS($lat)) * SIN(RADIANS(lat))))";
return DB::table('buildings')
->join('missions', 'building_id', '=', 'buildings.id')
->select('missions.*', 'buildings.lat', 'buildings.lng')
->orderBy(DB::raw($orderBy))
->get();
result:
{
"id": 5,
"building_id" : 2
...
"created_at": "2016-03-07 07:35:19",
"updated_at": "2016-03-07 07:35:19",
"lat": 33,
"lng": 55
}
But this returns quite ugly response and hard to work with. Since Mission have relation with a Building, I would like to load that table to the response too (Instead of displaying building_id). But with DB:Table() it's not possible(?)
{
"id": 5,
"building_id": 2
"building" : {
"id": 2
...
"lat": 33,
"lng": 55
}
...
}
This is the response I would like to get, and be sorted by lat/lng.
Is there any possible way to do this with Eloquents models?
Does this work to you?
$orderBy = "DEGREES(ACOS(COS(RADIANS($lat)) * COS(RADIANS(lat)) * COS(RADIANS($lng) - RADIANS(lng)) + SIN(RADIANS($lat)) * SIN(RADIANS(lat))))";
return Building::join('missions', 'building_id', '=', 'buildings.id')
->select(['missions.*', 'buildings.lat', 'buildings.lng'])
->with('missions')
->orderBy(DB::raw($orderBy))
->get();
PS: Don't forget to set the relation in your Building model, unless the with method will fail.

Resources