Eloquent laravel WhereIn All - php

I want to return all items with have all categories.
$items = DB::table('items')
->join('catitem_item', 'catitem_item.item_id', '=', 'items.id')
->whereIn('catitem_item.catitem_id', $cats)->paginate(10);
This query what I have now return items that have category 1 or 2 or 3.
What I need is return items that have category 1 and 2 and 3.
How can I achieve this?

Try this one:
$items = DB::table('items')
->join('catitem_item', 'catitem_item.item_id', '=', 'items.id')
->whereIn('catitem_item.catitem_id', $cats)
->groupBy('items.id')
->having(DB::raw('count(*)'), '=', count($cats))
->select('items.*')
->paginate(10);
With HAVING count(*) = 3 the query will only return items that have all listed categories.

Try like this:
Where $cats= [1,2,3];
$items = DB::table('items')
->join('catitem_item', 'catitem_item.item_id', '=', 'items.id')
->whereIn('catitem_item.catitem_id', $cats)
->paginate(10);
its return items for category 1 and 2 and 3.that means its use for AND opration.

Related

get ids from join in laravel

I am getting data from join in laravel but i cant get rides id using get or pluck method in query.
$datas = \App\Models\Order::find($id);
$new = explode(',',$id);
$orderss = DB::table('orders')
->join('jobs', 'jobs.order_id', '=', 'orders.id')
->join('rides', 'rides.job_id', '=', 'jobs.id')
->whereIn('orders.id', $new)
->get();
here is the data
enter image description here
i want to get data of rides.id from query
whenever i use get or pluck method i got error
`
$datas = \App\Models\Order::find($id);
$new = explode(',',$id);
$orderss = DB::table('orders')
->join('jobs', 'jobs.order_id', '=', 'orders.id')
->join('rides', 'rides.job_id', '=', 'jobs.id')
->whereIn('orders.id', $new)
->get('id');
`
enter image description here
In the second image you posted error show that 'id' field is ambiguous which means there are multiple columns named 'id' and it is true.
There are three 'id' columns coming from orders table, jobs table and rides table.
So you need to tell that which 'id' column you want to extract.
For this purpose you can try following code.
$orderss = DB::table('orders')
->join('jobs', 'jobs.order_id', '=', 'orders.id')
->join('rides', 'rides.job_id', '=', 'jobs.id')
->whereIn('orders.id', $new)
->get('rides.id')
OR
$orderss = DB::table('orders')
->join('jobs', 'jobs.order_id', '=', 'orders.id')
->join('rides', 'rides.job_id', '=', 'jobs.id')
->whereIn('orders.id', $new)
->select('rides.id')
->get()
these both should work and return you the collection of rides ids.

How can I separate out the Ids in tables joined within a Laravel Project

I have the following that joins together 3 tables, Images, Users, Profiles. The problem I have is that the result of the following only gives me 1 id field and that is the Id of the Profiles table. All 3 tables have their own Id fields.
Can I seperate it so that it is images.id, profiles.id and users.id?
$images = \App\Image::where('image_approved', '=' ,"feature_approved")
->join('users', 'users.id', '=', 'images.user_id')
->join('profiles', 'profiles.user_id', '=', 'images.user_id')
->get();
You can alias them like this:
$images = \App\Image::select([
'users.id as user_id',
'profiles.id as profile_id',
'images.id as image_id',
//... add the rest of the columns that you want to select here.
])
->where('image_approved', '=' ,"feature_approved")
->join('users', 'users.id', '=', 'images.user_id')
->join('profiles', 'profiles.user_id', '=', 'images.user_id')
->get();
or you can simplify it by using Eloquent relationships.
So in your Image model you would have:
public function user()
{
return $this->belongsTo(User::class);
}
public function profile()
{
return $this->hasOneThrough(Profile::class, User::class);
}
Then you can retrieve them:
$images = Image::with('user', 'profile')
->where('image_approved', '=' ,"feature_approved")
->get();
// now each $image in $images will have user and profile relationship
// $image->id
// $image->user->id
// $image->profile->id
Use alias in select like this:
->join('profiles', 'profiles.user_id', '=', 'images.user_id')
->select('images.*', 'users.*', 'profiles.*', 'images.id as imageID', 'profiles.id as profileId', 'users.id as usersId')
->get();

Displaying the average rating of every record that has the same ID and record with no rating

I want to display every record with their average rating and records with no rating with foreach loop. My problem is my code only displays records that has rating. Below is my code.
$packages = DB::table('packages')
->join('comments', function($join){
$join->on('comments.package_id', '=', 'packages.package_id');
})
->join('agents', function($join){
$join->on('packages.agent_id', '=', 'agents.id');
})
->select('comments.*', 'packages.*', 'agents.fname', 'agents.lname', 'agents.photo as agent_photo',
DB::raw('AVG(rating) as ratings_average'))
->groupBy('comments.package_id')
->orderBy('packages.created_at', 'desc')
->paginate(8);
$packages = DB::table('packages')
->leftJoin('comments', function($join){
$join->on('comments.package_id', '=', 'packages.package_id');
})
->join('agents', function($join){
$join->on('packages.agent_id', '=', 'agents.id');
})
->select('comments.*', 'packages.*', 'agents.fname', 'agents.lname', 'agents.photo as agent_photo',
DB::raw('AVG(rating) as ratings_average'))
->groupBy('comments.package_id')
->orderBy('packages.created_at', 'desc')
->paginate(8);
I solved my problem, i just changed inner join to left join.

Eloquent wherein with join multiple tables

I have 4 tables, items, listings, catitem_item, and item_listing.
items and listing is many to many relationship.
items and catitems is also many to many relationship.
catitems contains list of item's categories.
listings is like location where items located.
example listing shop A can have item chair and item chair have multiple catitem categories.
My goal is to get items which under list of categories such as category 1 AND 2 AND 3 ($cats) and with listing information where this item located.
So if there are 6 listings for chair, it will return 6 chair results.
This is the query I have so far.
$items = DB::table('items')
->join('catitem_item', 'catitem_item.item_id', '=', 'items.id')
->join('item_listing', 'item_listing.item_id', '=', 'items.id')
->join('listings', 'item_listing.listing_id', '=', 'listings.id')
->whereIn('catitem_item.catitem_id', $cats)
//->groupBy('items.id')
//->having(DB::raw('count(*)'), '=', count($cats))
->select('items.id', 'items.name', 'items.price', 'items.slug', 'item_listing.listing_id', 'listings.name as listing_name', 'listings.slug as listing_slug')
->get();
Note that the way you are trying to do it, you might get multiple rows per item (once per related listing). A better way would be to have an array of listings per item.
If you use eloquent models and you have setup the relations correctly, you could try the following:
$cats = [1, 2, 3];
$query = Item::with('listings');
foreach ($cats as $cat) {
$query->whereHas('catitems', function($q) use($cat) {
$q->where('id', $cat);
});
}
$items = $query->get();
Now every item shoud have a listings property. For example for the first item you can access the listings the following way:
$item1 = $items[0];
$listings1 = $item1->listings;
Note that whereHas() will probably create a correlated EXISTS subquery for every entry in the $cats array. If that is to slow, you can use a JOIN query like:
$items = Item::with('listings')
->join('catitem_item', 'catitem_item.item_id', '=', 'items.id')
->whereIn('catitem_item.catitem_id', $cats)
->groupBy('items.id')
->having(DB::raw('count(*)'), '=', count($cats))
->select('items.*')
->get();
If you don't use eloquent, you can also do the "eager loading" yourself.
$items = DB::table('items')
->join('catitem_item', 'catitem_item.item_id', '=', 'items.id')
->whereIn('catitem_item.catitem_id', $cats)
->groupBy('items.id')
->having(DB::raw('count(*)'), '=', count($cats))
->select('items.*')
->get()
->keyBy('id');
foreach ($items as $item) {
$item->listings = [];
}
$itemIds = $items->pluck('id');
$listings = DB::table('listings')
->join('item_listing', 'item_listing.listing_id', '=', 'listings.id')
->whereIn('item_listing.item_id', $itemIds)
->groupBy('listings.id')
->select('listings.*', DB::raw('group_concat(item_listing.item_id) as item_ids'))
->get();
foreach ($listings as $listing) {
$itemIds = explode(',', $listing->item_ids);
foreach ($itemIds as $itemId) {
$items[$itemId]->listings[] = $listing;
}
$listing->forget('item_ids');
}

If statement in Laravel Eloquent

I have two Models which are joined through three id's to one 1 id. The model AdviceProtocol had three ids defined: threshold_category1_id, threshold_category2_id and threshold_category3_id. These are all three linked to id from the model Categories. The threshold_cateogry_id's can be a number linked to the categories.id, or null.
In my query, I need to go through three of the threshold_catogory_ids and if they are NOT NULL, retrieve the categories.name. The query that I have now:
$advicePreparationsQuery = AdviceProtocol::select(['advice_protocols.name', 'advice_protocols.category', 'questions.name AS question_name', 'categories.name as Category_Name','categories.name as Category_Name2'])
->join('questions', 'advice_protocols.user_goal_id', '=', 'questions.id')
->join('categories', function ($join)
{
$join->on('advice_protocols.threshold_category1_id', '=', 'categories.id')->orOn('advice_protocols.threshold_category2_id', '=', 'categories.id')->orOn('advice_protocols.threshold_category3_id', '=', 'categories.id');
})
This query now returns the same category.name twice.
I have tried to look up how other people have solved this problem, but i couldn't find something accurate online.
I'd try three joins with three different alias and then grab the name for each category name of each different alias:
$advicePreparationsQuery = AdviceProtocol::select(['advice_protocols.name', 'advice_protocols.category', 'questions.name AS question_name', 'categories1.name as Category_Name','categories2.name as Category_Name2','categories3.name as Category_Name2'])
->join('questions', 'advice_protocols.user_goal_id', '=', 'questions.id')
->join('categories as categories1', 'advice_protocols.threshold_category1_id', '=', 'categories1.id')
->join('categories as categories2', 'advice_protocols.threshold_category2_id', '=', 'categories2.id')
->join('categories as categories3', 'advice_protocols.threshold_category3_id', '=', 'categories3.id');
Use group by name in query ie ->groupBy('category.name')
$advicePreparationsQuery = AdviceProtocol::select(['advice_protocols.name', 'advice_protocols.category', 'questions.name AS question_name', 'categories.name as Category_Name','categories.name as Category_Name2'])
->join('questions', 'advice_protocols.user_goal_id', '=', 'questions.id')
->join('categories', function ($join)
{
$join->on('advice_protocols.threshold_category1_id', '=', 'categories.id')->orOn('advice_protocols.threshold_category2_id', '=', 'categories.id')->orOn('advice_protocols.threshold_category3_id', '=', 'categories.id');
}
->groupBy('category.name'))

Categories