Laravel - Get an user who has specific relationships - laravel

I have a user with countries relationship. (hasMany)
user_id 1
country_id 1
user_id 1
country_id 2
...
What I want is to get those users who have both countries (country 1 and country 2) How can I do this? I'm reading http://laravel.com/docs/eloquent#querying-relations but I'm not very sure what to do.
edit: almost the solution
$users = \User::whereHas('countries', function($query) {
$countries_ids = [1, 2, 4];
$query->whereIn('users_countries.country_id', $countries);
})->get();

This will work as long as there are no duplicates in the pivot table (unique index for pair of fk keys for example):
$countries = [1,5,9];
User::whereHas('countries', function ($q) use ($countries) {
$q->whereIn('users_countries.country_id', $countries);
}, '=', count($countries) )->get();
In case there are duplicates, like:
user_id | country_id
1 | 1
1 | 2
1 | 1
Then you would need raw count(distinct ...) so you couldn't use whereHas, so I suggest this, which will be much faster:
$countries = [1,5,9];
User::join('users_countries as uc','uc.user_id', '=', 'users.id')
->whereIn('uc.country_id', $countries)
->having(DB::raw('count(distinct uc.country_id)'), '=', count($countries))
->groupBy('users.id')
->get(['users.*']);

You can do it the other way. Make the query on the country model. Add a function in the country model
public function user(){
return $this->belongsTo('user');//or if there is no user_id column in the countries table, use the ('model','local_key','foreign_key') pattern.
}
Then create an array with the country_ids, and que the country model.
$country_ids=array(4,67);
$countries=Country::where('id',$country_ids[0])->where('id',$country_ids[1])->get();
In order to get the users you should loop through like this
foreach($countries->user as $user)

Related

Laravel retrieve data from different tables and show in blade

I have 2 table A and B
A: id, b_id (which is the value of B's id & share many query rows), name, balance
B: id, country, state, age
In my view, I want to retrieve the data of A which has some specific id from B
Like: #foreach ($B_TABLE->id as $b_id)
{{ $b_id->sum('balance') }} <--- In this I want to retrieve the total sum of every 'balance' column from A table which has the id of $b_data in b_id column
What should be done in the Model/Controller to achieve that?
Try this Eloquent query with join:
$query = TableB::join('table_a', 'table_a.table_two_id', '=', 'table_b.id')
->select('table_b.id', \DB::raw("SUM(table_a.balance) as total_balance"))
->where('table_a.table_two_id', $id)
->groupBy('table_a.table_two_id')
->get();

Count and Groupby a value of a nested relationship in Laravel Eloquent

I have 3 models that are as follows
Orders
|id, customer_id, created_at, updated_at|
Customers
|id, name, zip_code, gender, created_at, updated_at|
Genders
|id, name, created_at, updated_at|
I am working on some sort of statistical dashboard. What I would like to do is to basically group the customers based on their gender so that I can have an output as below
Male = 60,
Female = 65 etc.
The Gender table basically contains records for each gender whilst the gender column on the customers table contains the gender id from which the gender name can be determined.
I have set up all the necessary relationships in the Model and I am able to run the code below which produces me a list with the genders however, I am struggling to group and then count how many customers are which.
$orders = Order::with('customer.gender')
->get()
->groupBy(['gender.name']);
You could do it with a couple of joins.
Gender::query()
->selectRaw('count(*) as count', 'genders.name')
->join('customers as c', 'genders.id', 'c.gender')
->join('orders as o', 'o.customer', 'c.id')
->groupBy('genders.name')
->get();
The model you start from (in this case Gender) doesn't really matter. Just that you join the other two tables.
Alternatively, with your approach maybe this would work:
Gender::query()
->with(['customers' => fn($customer) => $customer->withCount('orders')])
->get()
->mapWithKeys(fn($gender) => [
$gender->name => $gender->customers->sum('orders_count')
]);
Try this:
$orders = Order::with('customer.gender')
->select(DB::raw('count(*) as total'))
->get()
->groupBy(['gender.name']);

How can I do join with whereDoesntHave in Laravel

I'm trying to run a query in my Laravel 8.0 application. I've a problem doing join (circular) using the concept of whereDoesntHave() in Laravel. Since I'm using DB::table('...') and it has other conditions implemented, I'm having a brands table, projects table and project_associate_brand table, brand is in many-to-many relation with project, I want to find out the project counts in which brand and projects are not associated with each other, I'm trying to join the table twice one for getting projects associated with and other one to remove where it is not in relationship, so my query looks like:
$innerQuery = DB::table('brands as b')
->join('project_associate_brand as pabdoesnthave', 'b.id', '=', 'pabdoesnthave.brand_id')
->join('project_associate_brand as pab', function ($join) {
$join->on('b.id', '!=', 'pab.brand_id')
->where('pabdoesnthave.project_id', '!=', 'pab.project_id');
})
->join('projects as p', function ($join) {
$join->on('pab.project_id', '=', 'p.id')
->where('pabdoesnthave.project_id', '!=', 'p.id');
})
->select(DB::raw('b.id, b.title, COUNT(DISTINCT p.id) as projects_count'))
->whereNull('b.deleted_at')
->whereNull('p.deleted_at')
->groupByRaw('b.id');
return ProductBrandFilterResource::collection(DB::query()->fromSub($innerQuery, 't')
->select(DB::raw("
id,
`title`,
projects_count
"))
->orderBy('title', 'asc')
->groupBy('t.id')->get());
I'm unable get the desired results. To explain better I've table porject_associate_brand as:
brand_id project_id
1 1
1 2
1 3
2 1
2 3
If I want to get the list of brand where projects are not associated I get
id title project_count
1 ABC 3
2 PQR 3
For id 2 it is giving me 3 but actually it should be 1 as result.
Any better approach is appreciated. Thanks

how to retrieve multiple table data with multiple criteria in laravel eloquent?

I want to retrieve data from 4 different table using laravel eloquent with multiple criteria.
an Overview of my table;
table 1
id
name
table 2
id
name
year
table1_id
table 3
id
name
description
table2_id
table 4
id
name
quarter
table3_id
below are their relations
table 1
hasMany -> table 2
table 2
belongsTo ->table1
HasMany->table2
table 3
belongsTo ->table2
HasMany->table3
table 4
belongsTo ->table3
I'd like to fetch the data by resource show with two parameters
and i tried this
$Report = Table1::whereHas('tabke1', function($query){
$query->where('year', 'like','%'.$year.'%');
})
->with('table2')->whereHas('table3', function($query){
$query->where('quarter', 'like', '%'.$quarters.'%');
})
->get();
but im receiving syntax error.
How can I retrieve the data from multiple table with multiple filter?
i tried this table query to understand more what i expect
SELECT `table1`.*, `table2`.*, `table3`.*, `table4`.*
FROM `table1`, `table2`, `table3`, `table4`
WHERE ((`table2`.* year = 2019) AND (`table4`.* quarter = 1))
I reckon there are two queries to achieve the results.
The first query is something like:
Table1::whereHas('table2', function ($query) {
$query->where('year', 2019);
})
->whereHas('table2.table3.table4', function ($query) {
$query->where('quarter', 1);
})
->get();
The second query is something like:
Table1::select('table1.*')
->join('table2', 'table1.id', '=', 'table2.table1_id')
->join('table3', 'table2.id', '=', 'table3.table2_id')
->join('table4', 'table3.id', '=', 'table4.table3_id')
->where('table2.year', 2019)
->where('table4.quarter', 1)
->distinct()
->get();
Regarding performance, I prefer the second query.

laravel get unique results filter by a column value

I have a user table in which there is column Membership Id. I need to fetch rows which do not have duplicate value for Membership Id column. For Example, this is my table structure
ID Name Membership Id
1 xxx 123
2 xxx 124
3 xxx 124
4 xxx 125
In output, I want to skip rows which have duplicate values for Membership Id and want to fetch only last row so output should be row 1,3,4 from above example
Use a subquery JOIN:
$join = User::select('membership_id', DB::raw('max(id) id'))
->groupBy('membership_id');
$sql = '(' . $join->toSql() . ') as latest';
$users = User::join(DB::raw($sql), function($join) {
$join->on('users.membership_id', 'latest.membership_id')
->on('users.id', 'latest.id');
})->get();
In Laravel 5.6.17 you can use joinSub():
$join = User::select('membership_id', DB::raw('max(id) id'))
->groupBy('membership_id');
$users = User::joinSub($join, 'latest', function($join) {
$join->on('users.membership_id', 'latest.membership_id')
->on('users.id', 'latest.id');
})->get();
Via eloquent
User::select('Membership_Id')->distinct()->get();
Vie db facade
DB::table('users')->select('Membership_Id')->distinct()->get();
For Eloquent
MyModel::distinct()->get(['column_name']);
for you
User::distinct()->get(['Membership Id']);

Resources