Filter a elequent relationship by date - laravel

-- Laravel 8.* --
Hi, i am trying to respond, in a api, data about football, domain.test/api/fixtures/2020-11-06 should be giving a array of leagues with fixtures for the date given.
At this point I have App\Models\League with a a filter for fixtures hasMany.
/**
* Get all the fixtures from this league
*/
public function fixtures()
{
return $this->hasMany('App\Models\Fixture', 'league_id', 'id');
}
And in the FixturesController I call it with a whereHas:
$leagues = League::with('fixtures')->whereHas('fixtures', function($q) use ($date) { $q->where('date', $date); })->get();
return $this->responseWithSuccess(['leagues' => $leagues ]);
But this is returning the wrong answer.
"leagues": [
{
"id": 4,
"...",
"name": "Premier League",
"fixtures": [
{
"id": 62,
"...",
"date": "2020-10-17",
Help Please!
What am I doing wrong?
And Can somebody tell me the best way to debug errors like that?

Add the same function you have on the whereHas method to the with method.
In the way you're doing it, the whereHas is going to filter the Leagues that have a Fixture on that date, but the with is going to bring you all the Fixtures of each of those Leagues, not just those on the given date.
Another thing, for dates preferably use whereDate instead of just where.
That said, your query could look like this:
League::with(['fixtures' => function($q) use ($date) {
$q->whereDate('date', $date);
}])
->whereHas('fixtures', function($q) use ($date) {
$q->whereDate('date', $date);
})
->get();

Related

Laravel, eloquent, query: problem with retriving right data from DB

I'm trying to get the right data from the database, I'm retriving a model with a media relation via eloquent, but I want to return a photo that contains the 'main' tag stored in JSON, if this tag is missing, then I would like to return the first photo assigned to this model.
how i assign tags to media
I had 3 ideas:
Use orWhere() method, but i want more likely 'xor' than 'or'
$models = Model::with(['media' => function ($query) {
$query->whereJsonContains('custom_properties->tags', 'main')->orWhere();
}]);
return $models->paginate(self::PER_PAGE);
Raw SQL, but i don't really know how to do this i tried something with JSON_EXTRACT and IF/ELSE statement, but it was to hard for me and it was a disaster
Last idea was to make 2 queries and just add media from second query if there is no tag 'main'
$models = Model::with(['media' => function ($query) {
$query->whereJsonContains('custom_properties->tags', 'main');
}]);
$models_all_media = Model:: with(['media']);
return $models->paginate(self::PER_PAGE);
but i tried something like
for($i=0; $i<count($models); $i++) {
$models->media = $models_all_media
}
but i can't do this without get() method, beacuse i don't know how to change this to LengthAwarePaginator class after using get()
try using whereHas https://laravel.com/docs/9.x/eloquent-relationships
Model::with('media')
->whereHas('media',fn($media)=>$media->whereJsonContains('custom_properties->tags', 'main'))
->paginate(self::PER_PAGE);
as per your comment you can use
$models = Model::with(['media' => function ($query) {
$query->whereJsonContains('custom_properties->tags', 'main');
}])
->leftJoin('media', function ($join) {
$join->on('models.id', '=', 'media.model_id')
->whereNull('media.custom_properties->tags->main');
})
->groupBy('models.id')
->paginate(self::PER_PAGE);
return $models;

Querying to fetch relationship data in laravel

I am fetching post with the specific tag id and I have following code so far.
public static function getPostByTag($id) {
return Tag::with('posts')->whereHas('posts', function($q) use(&$id) {
$q->where('tags.id',$id);
})->get();
}
The data I am getting is working perfectly so far but now, I want to limit the data. What should I do to limit data?
I have tried following:
public static function getPostByTag($id) {
return Tag::with('posts')->whereHas('posts', function($q) use(&$id) {
$q->where('tags.id',$id);
})->take(5)->get();
}
But, it does not seem to work. Also, I want to list my post by according to latest date.
It seems you want to get post by the tag_id, you can just use Tag::where('id', $id)
If you want the latest posts, you can use ->latest() method, it will automatically order by created_at desc.
And you want to limit the posts, you need to limit it in with closure:
public static function getPostByTag($id){
return Tag::where('id', $id)->has('posts')
->with(['posts' => function($q) {
$q->latest()->limit(5);
}])->get();
}
You need to do in the following ways:
public static function getPostByTag($id){
return Tag::whereHas('posts', function($q) use(&$id){
$q->where('tags.id',$id);
}->with(['posts' => function($q) {
$q->orderBy('created_at', 'DESC')->take(5);
}])->get();
}

How To Use groupBy in whereHas laravel

i am using Metable in my project for creating meta for orders
but i have one problem
i want group orders that have same email
this is metable table image : image 1 image 2
i need code like this can work :)
Order::whereHas( 'meta', function($query) {
$query->where("key" , "gmail");
})->groupBy('meta.value')->get();
and this is meta relation that called by trait 'use Metable' in Order Model:
public function meta(): MorphMany
{
return $this->morphMany($this->getMetaClassName(), 'metable');
}
Thanks
This query may work, we start querying from the Meta model:
Meta::with('metable')
->whereHasMorph('metable', Order::class)
->where('key', 'gmail')
->get()
->groupBy('value')
->map(function ($metaCollection) {
return $metaCollection->map->metable->unique('id');
});
This is untested, but I would give it a try to retrive the models from the Order class:
Order::whereHas('meta', function($query) {
$query->where('key', 'gmail');
})->with(['meta' => function($query) {
$query->groupBy('value')
}])->get();
Try this solution instead:
Order::whereHas( 'meta', function($query) {
$query->where("key" , "gmail")
$query->groupBy('meta.value');
})->get();

Any way to do simple count of relations with different 'where' clauses?

I have this relation in User model
public function bulletins()
{
return $this->hasMany('App\Bulletins','owner');
}
in controller I getting count of bulletins:
dump(
User::where('id',Auth::id())
->withCount('bulletins')
->where('status','=',1)
->first()
);
This count all with status=1 but I also need status=0 and other parameters which in different table columns. On out I want something like this:
bulletin_counters->total =10//all
bulletin_counters->active =20//status=1
bulletin_counters->archive =30//status=0
bulletin_counters->deleted =40//deleted=1
etc...
Which is the best way to do this? I know that I can do many queries and manually assign this variables.
You should be able to customize the query which is generated by withCount
Try the following:
->withCount([
'bullentins as bullentins_total',
'bullentins as bullentins_active' => function($query) { $query->where('status', 1); },
'bullentins as bullentins_archive' => function($query) { $query->where('status', 0); },
'bullentins as bullentins_deleted' => function($query) { $query->where('deleted', 1); }
]);

Laravel filter relation's data by other relations data

I am trying to filter my tickets.tips.drawDates relation's data by other relation's column (results.draw_date) in an eager-loading query. Does anybody have any advice on how to accomplish that?
$products = Product::with([
'results' => function ($query) use ($drawDates) {
return $query->whereBetween('draw_date', $drawDates);
},
'tickets' => function ($query) use ($drawDateFrom) {
return $query->whereDate('valid_until', '>=', $drawDateFrom)->where('status', 'pending');
},
'tickets.tips',
'tickets.tips.drawDates' => function($query) {
return $query->whereNull('status')->whereDate('draw_date', 'HERE SHOULD BE draw_date COLUMN FROM results RELATION');
},
'prizes'
])->get();
You could try with the whereColumn() function, it is used to verify that two columns are equal, something like that:
return $query->whereNull('status')->whereColumn('draw_date', 'results.draw_date');

Resources