Fetching a single table data in nested style in Laravel - laravel

I am asked to load data from a single table like the following:
=================================
|id |dept | response | created_at |
=================================
|1 |FO | GOOD | 2018-05-20 |
|2 |FO | GOOD | 2018-05-20 |
|3 |IT | GOOD | 2018-05-20 |
|4 |FO | BAD | 2018-05-20 |
|5 |IT | GOOD | 2018-05-20 |
|6 |LO | BAD | 2018-05-20 |
|7 |IT | GOOD | 2018-05-20 |
|8 |IT | GOOD | 2018-05-21 |
|9 |LO | GOOD | 2018-05-21 |
=================================
they want me to display only records created_at 2018-05-20. and the desired output display in blade is like this:
FO
GOOD 2
BAD 1
IT
GOOD 3
BAD 0
LO
GOOD 0
BAD 1
when I use select distinct, it displays only one row of response data (only GOOD). The same thing happens when I use groupBy
here are my current codes:
Controller:
$date = new Carbon('2018-05-20');
$result = Result::select('dept', 'response')->where('created_at', '=', $date->toDateString())->groupby('dept')->get();
blade:
#foreach($result as $result)
{{$result->dept}}</BR>
{{$result->response}}</br></br>
#endforeach
The output I get:
FO
GOOD
IT
GOOD
LO
GOOD
I don't do the count yet because I still get this undesired result.
Is there a way to achieve the desired request with that single table?
EDIT I:
Based on Yrv16's answer, my controller goes like this:
namespace App\Http\Controllers;
use App\Result;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
public function index()
{
$date = new Carbon('2018-05-20');
$results = Result::select('dept', 'response', \DB::raw('COUNT(*) as count'))
->where('created_at', '=',$date->toDateString())
->groupby('dept','response')
->get();
$results = $results->groupBy('dept');
return view('result.index', compact ('results'));
}
and my blade:
#foreach($results as $result)
{{$result->dept}}</BR>
{{$result->response}}</br></br>
#endforeach
this gives me an empty page. but when i change this where('created_at', '=', $date->toDateString()) to where('created_at', '>=', $date->toDateString()) i get this error Property [dept] does not exist on this collection instance.

Use groupBy for two columns dept, response:
$date = new Carbon('2018-05-20');
$results = Result::select('dept', 'response', \DB::raw('COUNT(*) as count'))
->where('created_at', '=',$date->toDateString())
->groupby('dept','response')
->get();
Also result collection you can groupBy('dept') in order to display it like you want:
$results = $results->groupBy('dept');
Blade:
#foreach($results as $dept => $result)
{{$dept}}</BR>
#foreach($result as $item)
{{$item->response}} {{ $item->count }}
#endforeach
#endforeach

You can use collection manipulation for that:
$results = Result::where('created_at', '2018-05-20')
->get()
->groupBy('dept')
->map(function ($item) {
return $item->groupBy('response')->map(function ($responses) {
return $responses->count();
});
});
It will give you the following results:
print_r($results->toArray());
Array (
[FO] => Array (
[GOOD] => 2
[BAD] => 1
)
[IT] => Array (
[GOOD] => 3
)
[LO] => Array (
[BAD] => 1
)
)

Related

In Laravel, How to get data from 2 tables data which are not existing in both tables

table 1
| ID | val1 |
| 1 | a |
| 2 | b |
| 3 | c |
table 2
| ID | val1 |
| 1 | a |
| 2 | b |
I need to get the table1 data, which is not on table 2
$users_without_info = DB::table('users')->rightJoin('user_infos', 'users.email', '=', 'user_infos.email')
->select('users.*')
->latest()
->get();
I tried this command, doesn't work.
use inner join
$users_without_info = DB::table('users')
->join('user_infos', 'users.email', '!=', 'user_infos.email')
->select('users.*')
->latest()
->get();
if you have models then use relationships with the foreign key then in user model add relation
public function userInfo(){
return $this->hasOne(UserInfo::class);
}
and the query will be
$users_without_info=\App\Models\User::doesntHave('userInfo')->get();
if you don't have foreign key and want to use email as unique identifier then
public function userInfo(){
return $this->hasOne(UserInfo::class,'email','email');
}
Here is the solution,
The issue is in the join statement.
You can try this way to get the table-1(users) data, which is not on table-2(user_infos),
$users_without_info = DB::table('users')
->leftJoin('user_infos', 'users.email', '=', 'user_infos.email')
->whereNull('user_infos.email')
->get();
Hope you will fix it..

foreach in Laravel controller not looping over correctly

$customers = DB::table('customers')
->Join('customer_types', 'customer_types.id', '=', 'customers.customer_type')
->Join('countries', 'countries.id', '=', 'customers.country_id')
->select(
'customers.*',
'customer_types.customer_type_name',
'countries.country_name'
)
->get();
foreach ($customers as $result) {
$prices = Pricing::whereIn('id', explode(',', $result->pricelist_id))->get();
}
I have the above code what am trying to achieve is to use the first query to fetch the actual value contained in pricelist_id.
pricelist_id is a collection of many ids ([1, 2, 3]) like that but when I execute the code it returns same value in all rows how can I make it iterate correctly.
You could maybe key your array.
$customers = DB::table('customers')
->Join('customer_types', 'customer_types.id', '=', 'customers.customer_type')
->Join('countries', 'countries.id', '=', 'customers.country_id')
->select(
'customers.*',
'customer_types.customer_type_name',
'countries.country_name'
)
->get();
$prices = []
foreach ($customers as $result) {
$prices[$result->id] = Pricing::whereIn('id', explode(',', $result->pricelist_id))->get();
}
#foreach ($customers as $customer)
{{ $customer->id }},
....
#foreach ($price[$customer->id] as $price)
{{ $price->... }}
#endroreach
#endforeach
This is not ideal. You're making 1 extra query per customer. Instead of having a pricelist_id field in your customers table, you should make it add another table between customers and pricings
+-----------+ +----------+
| customers | +------------------+ | pricings |
+-----------+ | customer_pricing | +----------+
| id |---+ +------------------+ +---| id |
| ... | | | id | | | ... |
+-----------+ +--->| customer_id | | +----------+
| pricing_id |<---+
| ... |
+------------------+

Laravel ORM - filter by name

I'm newer to Laravel and trying to use ORM to filter my results. So in my database I have table one (Developers) and table two (Programs):
Developers
-------------------
ID. | Name |
------|------------
1 | Bluegreen |
2 | Dancer |
3 | Martin |
------|------------
Programs
-------------------------------------
id | developer_id | name |
------|------------------------------
1 | 12 | Program Test |
2 | 3 | Capital |
3 | 2 | Asus |
4 | 2 | Rich |
5 | 5 | Huna |
------|------------------------------
I'm trying to filter by the Program name and my code is filtering by Developer name. I can easily do this in raw sql but I'm trying to learn ORM, for some reason it's like super difficult for me to learn.
Here's my code:
$query = $request->get('search');
$developers = Developer::where('name', 'LIKE', '%'.$query.'%')->with('programs')->get();
I think this code will work.
DB::table('developers')
->join('programs','developers.id','=','programs.developer_id')
->where('programs.name', 'like', '%'.'Capital'.'%')
->select('programs.*','developers.name')
->get();
You can simply do this in a closure function in laravel with relationships. This will filter your record on program name and also developer name.
$developers = Developer::where('name', 'LIKE', '%'.$request->search.'%')
->with(['programs' => function($filter) use ($request) {
$filter->where('name','LIKE','%'.$request->search.'%');
}])->get();
If you want to only filter by program name then you can do it in this way
$developers = Developer::with(['programs' => function($filter) use ($request) {
$filter->where('name','LIKE','%'.$request->search.'%');
}])->get();
You can also write a condition if $request->search is empty then return all data. If it is not empty then only return the filtered data. I am just simply doing it but you can optimize the query later.
if($request->search != '')
$developers = Developer::with(['programs' => function($filter) use ($request) {
$filter->where('name','LIKE','%'.$request->search.'%');
}])->get();
else
$developers = Developer::with('programs')->get();

How to whereHas when use belongsToMany relation

I got a problem, When try to use whereHas in this case
Table users.
----------------
| id | name |
----------------
| 1 | AAA |
| 2 | BBB |
| 3 | CCC |
----------------
Table subjects.
------------------
| id | title |
------------------
| 1 | Subject 1 |
| 2 | Subject 2 |
------------------
Table subject_user.
------------------------
| user_id | subject_id |
------------------------
| 1 | 1 |
| 2 | 1 |
| 1 | 2 |
| 3 | 2 |
------------------------
in Subject Model
...
public function User()
{
return $this->belongsToMany(User::class, 'subject_user');
}
...
When I want to find subject by user_id with this query.
In this case Auth::id() == 1 and $request->user_id == 3
$subject = Subject::whereHas('User', function ($query) use ($request) {
$query->whereIn('user_id', [Auth::id(), $request->user_id]);
})->get();
With this query, I got subjects 1 and 2. That was a wrong result. That must got only subject 2.
Then I try this.
$subject = Subject::whereHas('User', function ($query) use ($request) {
$query->where('user_id', Auth::id())->where('user_id', $request->user_id);
})->get();
It would not get any subjects.
What query do I use in this case to get only subject 2.
#Lloople from your answer, I got an idea.
$subject = Auth::user()->Subject()->whereHas('User', function ($query) use ($request) {
$query->where('user_id', $request->id);
})->first();
Why not doing it backwards? You already have the logged in user, so if you define the relationship in the User model you can do
$subjects = auth()->user()->subjects;
Anyway, you don't need to check double the Auth::id()and $request->user_id. In fact, I'm not sure you can do this last one.
Edit after comments
$subjects = Subject::whereBetween(auth()->user()->id, $request->user_id)->get();
You will need to change the order from the inputs, in case $request->user_id is less than auth()->user()->idor it wouldn't work.

Laravel order by related table not working

I have this structure.
class Product extends Model{
public function office()
{
return $this->belongsTo(Office::class,'office_id');
}
}
I want to list products order by office.name.
this is the query
$res = \App\Product::with(['office' => function($q){
$q->orderBy('offices.name','asc');
}])->get();
this is the output loop
foreach($res as $key => $val){
print "<br />user: ".$val->id.", office: ".$val->office->id;
}
this is the Product data:
+----+--------+
| id | name |
+----+--------+
| 1 | Life |
| 2 | Cars |
| 3 | Health |
| 4 | House |
+----+--------+
this is the data in Office
+----+----------------+
| id | name |
+----+----------------+
| 1 | First office |
| 2 | working office |
+----+----------------+
The order by is not affecting the result.
same result, the order by like not existed.
Thanks
In your code you are simply "ordering" the offices by name, which means if each product had many offices, it would sort the offices alphabetically.
To sort (OrderBY()) a collection, the column has to be an attribute of the collection object. One solution could be to Join your models. SOmething like this might help you.
$res = Product::with('office')
->join('offices', 'products.office_id', '=', 'offices.id')
->select('products.*', 'offices.name')
->orderBy('office.name')
->get();

Resources