Eloquent select items with several where clause on same relationship column - eloquent

I have a User model with a hasMany relations to model Cart.
Cart model has (among others) user_id and campaign_id.
I want to make a request which will grab all the users who have a cart with a specific campaign_id and also at least one of a list of campaign ids.
I came up with this request
$alistUsers = User::whereHas('cart', function($query) use($campaignId, $campaignIds){
$query->whereIn('campaign_id', $campaignIds)
->where('campaign_id', '=', $campaignId)
;
})
->get()
;
which obviously returns 0 results since a cart item can't have several campaign_id.
I probably need to do something with sub selects but I can't find the correct answer.
If someone has an idea I'm all ears.
Thanks.

I finally ended up with 2 different queries
$userIds = User::whereHas('cart', function($query) use($campaignId, $campaignIds){
$query->where('campaign_id', '=', $campaignId);
})
->pluck('uuid')
->toArray()
;
$iKnowUsers = User::whereHas('cart', function($query) use($userIds, $campaignIds){
$query->whereIn('campaign_id', $campaignIds)
->whereIn('user_id', $userIds );
})
->get()
->count();
But I'm not really happy with that so if someone has a cleaner answer I'll be interested to see it :)

Related

TypeORM Postgres filter by relation count

context
I have Users collection and Recipe collection, ManyToMany relation between them
I'm new in this framework, wondering how can I do the following query:
count users with at least one recipe
count users without any recipes
I have found loadRelationCountAndMap is very useful in counting how many recipes a user has, but I can't seem to filter the total response according to this property.
I have tried this:
const users_without_recipes = await getRepository(User)
.createQueryBuilder('user')
.addSelect(['user.createdAt', 'user.email'])
.loadRelationCountAndMap('user.recipes_count', 'user.recipes')
.where('user.recipes_count = :count', {count: 0})
.getManyAndCount();
also tried to use postgres array_count but not sure how to integrate it with the typeORM framework
and help is very appreciated
You can do this with subqueries I think.
Something like this in SQL:
SELECT *
// ... other stuff
WHERE user.id IN (
SELECT u.id
FROM user u JOIN recipie r USING(id)
GROUP BY u.id
HAVING COUNT(*) > 10
)
Or in TypeORM:
// ...
.where(qb => {
const subQuery = qb.subQuery()
.select("u.id")
.from(User, "u")
// join users and recipies
.groupBy("u.id")
.having("COUNT(*) > :count", { count: 10 })
.getQuery();
return "user.id IN " + subQuery;
});
//...
I have stumbled upon this exact problem myself. I have fond a couple of sources that could help you find the solution. Your underlying problem is more general. If you turn on logging, you will probably see an error message something like:
Error column "user"."recipes_count" does not exist
The problem is that you are trying to use an alias. This question deals with this problem:
Using an Alias in a WHERE clause
I hope you are more successful then me, but I decided to use a workaround after a log trial and error. I am sure there is a better way. If you manage to find it, please let me know.
(If you want to get back the list of user entities, without the user.recipes_count property, include the last .map as well.)
const users_without_recipes = await getRepository(User)
.createQueryBuilder('user')
.loadRelationCountAndMap('user.recipes_count', 'user.recipes')
.getMany();
return users_without_recipes
.filter((user) => user['user.recipes_count'] === 0)
.map(({recipes_count, ...otherProperties}) => otherProperties);

Laravel eloquent search both table in one to many relationship table

My two table Member and Deposit there has one to many relationship one member has multiple deposit in Deposit table i want to search by multiple column both table which will have to match.
This is my Member Table
1.id,
2.branch_id,
3.village_id,
4.user_id,
5.name,
6.phone,
7.email,
8........
My Deposit Table
1.meber_id,
2.user_id
3.deposit_date,
4.deposit_amount,
5.total_amount,
6..........
My Controller Code
$depo = Deposit::with(['member'=>function($query){$query->where('branch_id',$request->branch_id)->where('status','running')->get();}])->where('user_id',$request->user_id)->whereDate('deposit-date','>=',$from_date)->whereDate('deposit-date','<=',$to_date)->get();
if i do that then ....$query->where('branch_id',$request->branch_id)->get()..... section is not working please help me any one
Try this:
$depo = Deposit::whereHas('member', function($query) use ($request){
$query->where([
['branch_id' => $request->branch_id],
['status'=> 'running']
])
})
->where('user_id',$request->user_id)
->whereDate([
['deposit-date','>=',$from_date],
['deposit-date','<=',$to_date]
])->get();
Your question is quite ambiguous, but looks like you need to use the $request in the with function.
$deposits = Deposit::with(['member' => function ($query) use ($request) {
$query->where('branch_id', $request->branch_id)
->where('status', 'running')->get();
}])->where('user_id', $request->user_id)
->whereDate('deposit-date', '>=', $from_date)
->whereDate('deposit-date', '<=', $to_date)
->get();
But the with method wont filter down your query it will simply limit the number of members returned with all the deposits. It's not searching in the member table.
UPDATE 04/12/2018
Without checking the docs at all, and completely off the top of my head.
Deposit::with('member', function($query) use($request){
$query->where('branch_id', $request->branch_id)
->orWhere('village_id', $request->village_id)
})->where(function($query) use($request) {
$query->where('user_id', $request->user_id)
->whereDate('deposit-date', '>=', $from_date)
->whereDate('deposit-date', '<=', $to_date)
})->orWhereHas('member', function($query) use($request){
$query->where('branch_id', $request->branch_id)
->orWhere('village_id', $request->village_id)
})->get();

Laravel Mongo GroupBy And count in an efficient manner

I have an authors collection that has a many-to-many relation to a posts collection. The posts collection has a category field which can be, for example, "Suspense", "Drama", "Action", etc.
I need to go through my entire posts collection and group by the category fields and also have the associated counts.
This is what I have so far:
$authors = Author::where('active', true)->get();
foreach ($authors as $author){
foreach ($author->posts()->groupBy('category')->get() as $data){
// Do some logic
}
}
Basically the output I am expecting is an array with category as keys and the counts as a value. So if I do $a['Drama'] it gives me count of how many times that author wrote a post with that category.
I can probably figure it out by working in my loop logic above but it does not look very efficient. Should I look at aggregation? If so can someone get me started?
Try this:
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
$authors = DB::collection('authors')
->where('active', true)
->get();
// Laravel >= 5.3 would return collection instead of plain array
$authors = is_array($authors) ? Collection::make($authors) : $authors;
$authors->map(function ($author) {
return $author
->posts()
->groupBy('category')
->get()
->map(function ($collection) {
return $collection->count();
});
});

Laravel 5.2 eloquent query

i have 2 table Jobs and Departments (a job belong to a department) and i want to get some jobs with its department.
Here is the code i have to modify:
$query = Job::query()->where('status', 2);
if($input['title']!=""){
$query->where('title', 'like', '%' . $input['title'] . '%')->get();
}
if($input['location'] != ""){
$query->where('location', '=', $input['location']);
}
if($input['recruiters'] != ""){
$query->where('recruiter_id','=', $input['recruiters']);
}
$jobs = $query->paginate(5);
return $jobs;
query variable don't have method join for me. I try with but it not work.
There are any solution for join or to make other query via DB but title,location,recruiters variables is not always be set.
Sorry for my bad English and thanks for your consider.
Have a look at Eloquent Relationships: https://laravel.com/docs/5.1/eloquent-relationships#defining-relationships
You basically define the relationship between Job and Depertment in the Model and later call $job->department()->name (this is an example call) to get the name of the attached department.

Laravel and Eloquent: Specifying columns in when retrieving related items

This is a followup post to: Laravel 4 and Eloquent: retrieving all records and all related records
The solution given works great:
$artists = Artist::with('instruments')->get();
return \View::make('artists')->withArtists($artists);
It also works with just:
$artists = Artist::get();
Now I'm trying to specify the exact columns to return for both tables. I've tried using select() in both the statement above and in my Class, like this:
ArtistController.php
$artists = Artist::select('firstname', 'lastname', 'instruments.name')->get();
or:
$artists = Artist::with(array('instruments' => function($query) {
$query->select('name');
}))->get();
(as suggested here and while this doesn't throw an error, it also doesn't limit the columns to only those specified)
or in Artist.php:
return $this->belongsToMany('App\Models\Instrument')->select(['name']);
How would I go about getting just the firstname and lastname column from the artists table and the name column from instruments table?
Not sure what I was thinking. I think working on this so long got me cross-eyed.
Anyhow, I looked into this a lot more and searched for answers and finally posted an issue on GitHub.
The bottom line is this is not possible as of Laravel v4.1.
https://github.com/laravel/laravel/issues/2679
This solved it:
Artists.php
public function instruments() {
return $this->hasMany('App\Models\Instrument', 'id');
}
Note that I changed this to a hasMany from a belongsToMany which makes more sense to me as a musicians (or Artist) would have many Instruments they play and an Instrument could belong to many Artists (which I also alluded to in my previous questions referenced above). I also had to specify 'id' column in my model which tells the ORM that instrument.id matches artist_instrument.id. That part confuses me a bit because I thought the order for hasMany was foreign_key, primary_key, but maybe I'm thinking about it backwards. If someone can explain that a bit more I'd appreciate it.
Anyhow, the second part of the solution...
In ArtistsController.php, I did this:
$artists = Artist::with(array(
'instruments' => function($q) {
$q->select('instruments.id', 'name');
})
)->get(array('id', 'firstname', 'lastname'));
That gives me exactly what I want which is a collection of Artists that contains only the firstname and lastname columns from the artists table and the name column for each of the instruments they play from the instruments.
$artists = Artist::with(array('instruments' => function ($query) {
$query->select('id', 'name');
}))->get('id', 'firstname', 'lastname');