eloquent query condition based on relation - php

Results(game_id, score)
Games(start, end, threshold)
Given a timestamp:
I want to find all results that belong to a game with a start & end time containing the timestamp time and where the result score is above the game threshold.
I have already managed to query for the time condition, but how can I additionally query for Results.score > games.threshold?
Results::whereHas('game', function($q) use ($timestamp) {
$q->where('start', '<=', $timestamp)
->where('end', '>=', $timestamp)
})->with('game')->get()

Try to use whereRaw inside whereHas and check if it works:
Results::whereHas('game', function($q) use ($timestamp) {
$q->where('start', '<=', $timestamp)
->where('end', '>=', $timestamp)
->whereRaw('results.score > games.threshold');
})->with('game')->get();

Related

How to add days in querying date? laravel

How can we add days in the date that we're querying using laravel eloquent?
Something like this:
Post::where('created_at + 7 days', now()->toDateTimeString())
->where('created_at', '<', now()->toDateTimeString())
->get();
My logic is like this one
today >= created_at && today <= created_at + 4
Is there some correct syntax to achieve this one?
One of the ways to compare from date time is using the calculated Carbon like below:
Post::where('created_at', '>=', now()->addDays(4)->toDateTimeString()
->get();
It will display only posts which have created_at greater than 4 days from today.
For date range filter, you can use between scope like:
$startDate = now()->subDays(4)->toDateString();
$endDate = now()->toDateString();
$filteredPosts = Post::whereBetween('created_at', [$startDate, $endDate])->get();
For more information about filter, you could visit Laravel Query Builder
You can use whereDate method:
Post::whereDate('created_at', 'like', now()->subDays(4))->get();
or
Post::whereDate('created_at', '>=', now()->subDays(4))->get();

Check date range is not already booked in Laravel 6?

I am working in an online bike booking system where the customer can book a bike for a particular date-time range. If another customer books the same bike for a specified date-time range, I have to check whether the bike is already booked or not. My database table reservations looks like this:
id bike_id start_date end_date
1 1 2019-05-04 14:30 2019-05-04 15:30
1 1 2019-05-04 16:30 2019-05-04 18:30
The query:
Reservations::where('bike_id', $yacht)
->where(function ($query) use ($startTime, $endTime) {
$query->where(function ($query) use ($startTime, $endTime) {
$query->where('start_date', '<', $startTime)
->where('end_date', '>', $startTime);
})
->orWhere(function ($query) use ($startTime, $endTime) {
$query->where('start_date', '>', $endTime)
->where('end_date', '<', $endTime);
});
})
->count();
Unfortunately, the code does not seem to work. It does not check the condition properly. How to do the desired check properly using the given inputs?
Namoshek's answer, based on your code, is correct. Personally, I find all the nested functions hard to read. They're not avoidable in a query like this, but they can be reduced:
$bike = Bike::findOrFail($yacht);
$conflict = $bike->reservations()
->whereBetween('start_date', [$startTime, $endTime])
->orWhereBetween('end_date' [$startTime, $endTime])
->orWhere(fn ($q) => $q->where('start_date', '<', $startTime)->where('end_date', '>', $endTime))
->exists();
if ($conflict) {
abort(409);
}
// continue saving the reservation
I'm assuming that you have correctly set up relations between your Bike and Reservation models, so can take advantage of them to make the code more readable still. (And you'll probably be finding that bike object later in the code anyway.)
What you want to check is whether the start date-time or the end date-time of the new booking lies within any existing record. In other words, there is two cases, as you already identified correctly, where one deals with the start time of the new booking and one with the end time. If any (or both) of them lie within an existing booking, the check failed.
use Illuminate\Database\Eloquent\Builder;
$similarBookingExists = Reservations::query()
->where('bike_id', $yacht)
->where(function (Builder $query) use ($startTime, $endTime) {
$query->where(function (Builder $query) use ($startTime) {
$query->where('start_date', '<=', $startTime)
->where('end_date', '>=', $startTime);
})
->orWhere(function (Builder $query) use ($endTime) {
$query->where('start_date', '<=', $endTime)
->where('end_date', '>=', $endTime);
});
})
->exists();
In short, the only mistake you made were the comparison operators < and > of the second case for $endTime.

MySQL: Validate for date range within rate range (laravel optional)

Hey guys (and girlies)
Can someone point out to validate / search for a date range within a date range? I am using Laravel PHP but raw SQL will be perfect as well.
I want to validate if a date range exists, within a date range. Basically I want a solid validation to avoid overlapping date ranges.
Example (and the concept I have at the moment) (laravel syntax)
->where('start_date','>=',$myrange_start)
->where('start_date','<=',$myrange_end)
Which will validate for for a start date in the database between the date range
and
->where('start_end','>=',$myrange_start)
->where('start_end','<=',$myrange_end)
Which will validate for for an end date in the database between the date range
And which has also kind of worked for me is
->whereRaw('? between start_date and end_date', [$today])
however, what I want to achieve is to say something like
->whereRaw('? between start_date and end_date', [$myrange_start, $myrange_end])
so see if there are date ranges which
a) start: on start, between start and end, on end
b) start: on end
c) end: on start, between start and en, on end
d) start BEFORE start date and ends AFTER ends date
e) start AFTER start date and ends BEFORE end date
Is this possible?
This is the overlapping range problem, and to quote this canonical SO answer, the WHERE clause should be something like:
WHERE new_start < existing_end
AND new_end > existing_start;
Translating this to Laravel code:
->where('start_date', '<', $myrange_end)
->where('start_end', '>', $myrange_start)
This would return true if there is an overlap between the two ranges. If instead you want to find out if there isn't an overlap, then we can try:
->where('start_date', '>=', $myrange_end)
->orWhere('start_end', '<=', $myrange_start)
Laravel official docs laravel docs whereBetween
ModelName::whereBetween('date_field', [ $start_Date, $end_date ])->get();
Okay, think this should then work. you guys can comment
where(function ($q) use ($start, $end) {
$q->where('start_date', '>=', $start)
->where('start_date', '<=', $end);
})
->orWhere(function ($q) use ($start, $end) {
$q->where('end_date', '>=', $start)
->where('end_date', '<=', $end);
})
->orWhere(function ($q) use ($start, $end) {
$q->where('start_date', '<', $start)
->where('end_date', '>', $end);
});

Eloquent: get only the date from timestamp

I want to get all the entries of a specific day for a user.. I don't know how to format the query.
public function getEntry()
{
$entries = Journal::where('id', '=', Auth::id())
->where('created_at', '=', '\Carbon\Carbon::now()->format("l j F Y")')
->get()->first();
return view('home')->with(compact('entries'));
}
I do not know how to format that 'created_at' to match the server time. Any help will be largely appreciated. Thank You.
Use whereDate() to get all entries for the specific day:
->whereDate('created_at', Carbon::today());
Or use whereBetween():
->whereBetween('created_at', [Carbon::now()->startOfDay(), Carbon::now()->endOfDay()])
Or simple where():
->where('created_at', '>', Carbon::now()->startOfDay())
->where('created_at', '<', Carbon::now()->endOfDay())

Laravel - Advanced Carbon Date Query

I'm trying to write a certain query but I'm failing with it and I'm looking for some help
Here's what I want to do
SELECT all items WHERE created_at is from before this month (July, June,...), and also select the first 3 which are created during this month
this is what I currently have. I've tried numerous times, but I can't figure out the right "WHERE" case
$offertes = DB::table('offertes')
->select('*')
->where('receiver_id', $user_id)
...
->orderby('seen')
->orderby('created_at','desc')
->get();
Something like this should work:
$time = new Carbon\Carbon('first day of this month'); // Get first day of the month.
$time->setTime(0, 0, 0); // Set time to 00:00:00.
....
->where('created_at', '<', $time)
->where(function($q) {
$q->where('created_at', '>', $time)
->orderby('created_at','asc')
->take(3)
})
->get;

Categories