Laravel Eloquent Many-to-Many query whereIn - php

In my application I have updated a relationship from one-to-many to many-to-many and I'm trying to figure out a way to persist associated functionality.
Let's say I have two related tables, e.g. dogs and owners. If I have an array of owners and I'm trying to get a list of dogs id's for those owners, how should I do it eloquently?
Similar question was asked here:
https://laracasts.com/discuss/channels/laravel/getting-many-to-many-related-data-for-an-array-of-elements
So, How would I get the Dog models where Owner is in an array ?
Same thing as $associatedDogs = Dog::whereIn('owner_id',$ListOfOwners)->get(); is for a One-To-Many relationship, but for Many-to-Many.

Use the whereHas() method:
$dogs = Dog::whereHas('owners', function($q) use($ownerIds) {
$q->whereIn('id', $ownerIds);
})->get();

I tried the two suggested solutions but I was getting an error that said that id was not unique.
I solved like this:
$dogs = Dog::whereHas('owners', function($q) use($ownerIds) {
$q->whereIn('owner_id', $ownerIds);
})->get();

Try
$associateDogs = Dog::with(['owners' => function($query) use ($listOfOwners) {
$query->whereIn('id', $listOfOwners);
}])->get();

Related

laravel elequent way to find single row from table

hello I am new to laravel and maybe I am a bit confused between eloquent and query builder way for writing a query but anyway can you please tell me what could be the best eloquent way to retrieve info like this in laravel 6 or 7
User > hasMany > Recipes
Recipe > belongsTo > User
I want to check if user id 2 present in users table then get only one post which id is 3
Query builder is for explicitly building SQL queries, and does not return instances of your models. Eloquent query builder, is similar but the result will contain the model(s) loaded with all their attributes, and has some handy functions for querying the relations you define in your models.
Given the limited information in your post, I am assuming when you say a post, you mean a recipe:
Query Builder:
DB::table('users')
->join('recipes', 'recipes.user_id', '=', 'users.id')
->select(['users.some_col', ... 'recipes.some_col'])
->where('users.id', 2)
->get();
If you have your models setup with the relations. You can use Eloquent like so:
User::where('id', 2)->with('recipes')->get();
If I understand you correctly it would be like this:
User::whereId($userId) //asuming it is 2
->with(['recipes' => function($q) use($recipeId) {
$q->where('id', $recipeId); //assuming it is 3
}])->first();
you can do this if i understand correctly:
$user = User::findOrFail(2); //auto 404 if user not found
$recipe = $user->Recipes()->where('id',3)->first();
You may use conditional eager loading for better performance.
$userId = 2;
$receiptId = 3;
$user = User::with(['receipts'=> function ($query) use($receiptId){
$query->where('id', $receiptId);
}
])->find($userId)

loading relationship with groupBy laravel

I have a query which selects some relationships and groups by the accommodations to remove the duplicate accommodations. But now when I want to load the discount realtion on rooms, it doesn't work because I select only the accommodation_id.
Here is my code:
$data = AccommodationRoom::with('accommodation.city', 'accommodation.accommodationFacilities', 'accommodation.gallery','discount')
->select('accommodation_id')
->whereHas('roomCapacityHistory', function ($query) use ($from_date, $to_date) {
$query->whereDate('from_date', '<=', $from_date);
$query->whereDate('to_date', '>=', $to_date);
})
->whereHas('accommodation', function ($query) use ($searchCity) {
$query->where('city_id', $searchCity);
})
->groupBy('accommodation_id')
->get();
Now if I add the id to the select it would be fine, but my groupBy doesn't work and gives me an error in this case. So I need a solution to get all my accomodations with the listed relations.
As you are looking for all your accommodations with some related models, you should actually select from your Accommodation model. This will work out of the box for the first three relations but will require some tweaking for the discount relation. The simpliest solution is to create a HasManyThrough relation on the Accommodation model:
class Accommodation extends Model
{
public function discounts()
{
return $this->hasManyThrough(Discount::class, AccommodationRoom::class);
}
}
Note: this expects your models to use foreign key columns named by convention; for different names you will need to pass the custom foreign key names as additional parameters according to the documentation.
With this relation set up, you can then use a query like the following:
$data = Accommodation::with('city', 'accommodationFacilities', 'gallery', 'discounts')
->whereHas('accommodationRooms.roomCapacityHistory', function ($query) use ($from_date, $to_date) {
$query->whereDate('from_date', '<=', $from_date);
$query->whereDate('to_date', '>=', $to_date);
})
->where('city_id', $searchCity)
->get();
Further explanation as asked for in the comments:
HasManyThrough builds a virtual relation between two models using a third model in between. Imagine you have Post, Comment and Like as models. One Post can have many Comments and one Comment can have many Likes:
has many has many
Post -----------------> Comment -----------------> Like
1 n 1 n
In this case we also know that one Post can have many Likes. And this is exactly the knowledge we utilize when using HasManyThrough. We simply tell Eloquent that a Post has many Likes, connected by the Posts in between:
has many has many
Post -----------------> Comment -----------------> Like
1 n 1 n
has many through Comment
Post ------------------------------------------------> Like
1 n

multiple "has many through" with eloquent of laravel

I came accros a problem with laravel's ORM, eloquent and found no solution yet.
I have some tables as follows
Team
- id
- name
User
- id
- name
- role
- team_id
Student_Info
- id
- user_id
- data1
- data2
- etc ...
Project
- id
- student_id
- name
Now, I want to query all projects a certain team, where team = 'some team'
Now the thing here is, without an ORM, it's simple, I would have done multiple joins in raw SQL.
However, because all these tables have a common column "name" I will have to alias all this stuff, which is really boring
With eloquent I can't find a way to do this query using "has many through" because it only allows on intermediate and I can't do a raw SQL as the alis thing is really a pain in the ass and as it would be very difficult to map the result to laravel's Models
There is no native relationship for this case.
I created a HasManyThrough relationship with unlimited levels: Repository on GitHub
After the installation, you can use it like this:
class Team extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function projects() {
return $this->hasManyDeep(Project::class, [User::class, StudentInfo::class],
[null, null, 'student_id']);
}
}
$projects = Team::where('name', 'some team')->first()->projects;
Try with relationship existence. This assumes you have all relationships properly defined
$projects = Project::whereHas('students.user.team', function ($query) {
$query->where('name', '=', 'some team');
})->get();
That's 3 levels of nesting. Never tested. However, if you already define a Project-User relationship via hasManyThrough() you can shorten it to 2 levels only.
$projects = Project::whereHas('user.team', function ($query) {
$query->where('name', '=', 'some team');
})->get();
Those will give you the data for projects only. If you also want the the intermediate data, use eager loading instead with with(). Just replace whereHas() by with().
$projects = Project::with('user.team', function ($query) {
$query->where('name', '=', 'some team');
})->get();

Laravel RelationShip (join with where)

I need help with Laravel 5 (using Eloquent)
I have 2 tables...
Model Driver
drivers
id
company
Model DriverOnline
drivers_online
id
name
driver_id
I need to search for a result on (company=1 and driver_id=driver.id).
Please help me!
If you want to only fetch Driver based on a condition, you can just do this:
Driver::with('online')->where('company', 1)->get();
If the clause is on the relationship, use with and specify a query on that.
$company = 1;
$drivers = Driver::with(['online' => function($query) use ($company)
{
$query->where('company', $company);
}]);
See "Eager Load Constraints":
https://laravel.com/docs/5.0/eloquent
Take note of my use. This allows you to include variables from the scope into your Closure instance.
And be aware, if you use either solution, you must set up a relationship. Consult the link I shared with more information on that.
Edit: As per our conversation.
$drivers = Driver::where('company_id','=',1)
->with('driversOnline')
->whereHas('driversOnline', function($query) {
$query->where('online','=',1);
})
->get();

Referencing foreign key data in WHERE clause in Eloquent

I have two tables Songs (belongsTo App\Host) and Hosts (hasMany App\Song). My Songs table has an attempts column and my Host table has a skip_threshold. I would like to query out all Songs that have not met its related Host's skip threshold.
How can I do this?
I have tried something like this:
return $songs = Song::whereIn('host_id', $available_hosts)
->where('attempts', '<', $songs->host->skip_threshold)->get();
I've attempted to make use of Eloquent relationship querying, but from testing I see this won't work. I would like to try and use Eloquent to do this so I can take advantage of eager loading related data in my blade templates.
You could try
$songs = Song::whereHas('host', function($query) {
$query->where('skip_threshold', '>', DB::raw('songs.attempts'));
})->get();
If I'm understanding what you're looking for, you can chain together where clauses, like so:
$songs = Song::whereHas('host', function($query) {
$query->where('skip_threshold', '>', DB::raw('songs.attempts'));
})->whereIn('host_id', $available_hosts)->get();

Categories