Unique results from the Laravel database 5.8 - php

I am beginner in Laravel. I use in my project Laravel 5.8.
I have schema:
Schema::create('statistics', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('company_id')->unsigned();
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$table->text('agent')->nullable();
$table->date('date')->nullable();
$table->ipAddress('ip');
$table->bigInteger('user_id')->default(0);
$table->bigInteger('quest_id')->default(0);
$table->string('browser', 70)->nullable();
$table->string('platform', 70)->nullable();
$table->string('language', 12)->nullable();
// $table->string('url_address', 160)->nullable();
$table->engine = "InnoDB";
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
});
I get statistics from this function:
public function generateStatistics(string $dateFrom, string $dateTo, int $id)
{
return Statistics::whereBetween('date', [$dateFrom, $dateTo])->where('user_id', $id)->get();
}
This function returns all the results from the database to me and works correctly. I need to redo this function to display unique results. Unique result = unique ip on the selected day.
How to do it?

you need to add a dictinct ip
public function generateStatistics(string $dateFrom, string $dateTo, int $id)
{
return Statistics::whereBetween('date', [$dateFrom, $dateTo])->where('user_id', $id)->distinct('ip')->get();
}
or you can group by ip
public function generateStatistics(string $dateFrom, string $dateTo, int $id)
{
return Statistics::whereBetween('date', [$dateFrom, $dateTo])->where('user_id', $id)->groupBy('ip')->get();
}

What do you mean by unique? get the list of distinct IPs on that range? this would be like this:
public function generateStatistics(string $dateFrom, string $dateTo, int $id)
{
return Statistics::whereBetween('date', [$dateFrom, $dateTo])
->where('user_id', $id)
->select('ip')
->distinct()
->get();
}
EDIT: I saw that the thing you want is not the IPs values just the count for the statistics.
Transforming to MYSQL should be something like this (This maybe helps you to your code):
SELECT COUNT(id), ip
FROM statistics
WHERE user_id = {{id}} AND date BETWEEN {{dateFrom}} AND {{dateTo}}
GROUP BY ip;
So this will return the number of request grouped by IP. The SUM of all counts will give you the total of request, the count of IPs will give you the total of UNIQUE request.
To Laravel:
$requestPerIp = Statistics::whereBetween('date', [$dateFrom, $dateTo])
->where('user_id', $id)
->select('ip', DB::raw('count(*) as total'))
->groupBy('ip')
->get();
For the total unique request just:
$numberOfUniqueRequest = count($requestPerIp);

Related

Trying to update integer in database by using increment function in laravel

I want to add 1 to my previous karma value in my database.
Here's what I am doing in my controller:-
public function response(Request $request, $id)
{
$globalPost = PublicAnswer::find($id);
if($request->resp == "normal")
{
$answered_by = DB::table('users')
->where('id', $globalPost->answered_by)
->increment('karma', +1);
}
}
Here's my database:-
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->integer('karma')->nullable();
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
If I replace increment function with update this is the error that I am getting:-
Argument 1 passed to Illuminate\Database\Query\Builder::update() must be of the type array, string given,
I cannot see any errors and the karma attribute is null.
can anyone tell me whats wrong with my codes.
DB::table('users')
->where('id', $globalPost->answered_by)
returns a Illuminate\Database\Query\Builder ;
Illuminate\Database\Query\Builder has an increment function
public function increment($column, $amount = 1, array $extra = [])
and an update function
public function update(array $values)
so you can try
DB::table('users')
->where('id', $globalPost->answered_by)
->increment('karma');
or this, this would set karma to 1
DB::table('users')
->where('id', $globalPost->answered_by)
->update(['karma'=>1]);
if you want use update set karma=karma+1
use Illuminate\Database\Query\Expression;
DB::table('users')
->where('id', $globalPost->answered_by)
->update(['karma'=>new Expression('karma + 1')]);
According to the docs https://laravel.com/docs/8.x/queries#increment-and-decrement you simply want increment('karma') to increment by 1
The second argument may optionally be passed to control the amount by which the column should be incremented or decremented. You do not need to precede the amount with the plus sign either as increment and decrement mean add or subtract respectively

Laravel 6 query same table with different where clause

I have campaign_report table like this
Schema::create('campaign_report', function (Blueprint $table) {
$table->bigIncrements('id');
$table->date('report_date');
$table->bigInteger('user_id');
$table->bigInteger('campaignId');
$table->double('cost',12,2);
$table->timestamps();
});
I am trying to get all yesterday's campaign reports.
$campaignReports = CampaignReport::where(['report_date' => "$yesterday", 'user_id' => Auth::user()->id])->orderBy('report_date', 'desc')->paginate(25);
Above query is returning all campaigns where report_date is equal to $yesterday.
Along with this query I also want to get the cost value of each campaign where report_date is day before yesterday matching the campaignId column. I want to show the difference of cost between yesterday's campaigns and day before yesterday's campaigns.
like
foreach($campaignReports as $campaignReport)
{
$difference = $campaignReport->cost - $campaignReport->dayBeforeYesterdayCost;
}
Can anyone help me in building this query using Query Builder or Eloquent?
You can write a relation in your CampaignReport model that calculate difference between yesterday's cost and the day before that
public function dayBeforeYesterdayCost() {
$dayBeforeYesterday = Carbon::parse($this->report_date)->subDays(1); //return date of day before yesterday
$dayBeforeYesterdayCost = CampaignReport::where('campaignId', $this->campaignId)
->where('report_date', $dayBeforeYesterday)
->first();
return $dayBeforeYesterdayCost ? $dayBeforeYesterdayCost->cost : 0;
}
public function lastDayDifference() {
$difference = $this->cost - $this->dayBeforeYesterdayCost;
return $difference;
}
Now you can return $campaignReports with lastDayDifference relation like this:
$campaignReports = CampaignReport::where(['report_date' => "$yesterday", 'user_id' => Auth::user()->id])
->with('lastDayDifference')
->orderBy('report_date', 'desc')
->paginate(25);
At the end you have one object attached to your every single $campaignReport
Group by date(report_date) which will just give you the date part, order by the same descending, then just take the values for yesterday and the day before. Something like:
CampaignReport::select(DB::raw('date(report_date) report_date', DB::raw('count(*) as count'))
->where('report_date','>=',$twoDaysAgo)
->where('user_id', Auth::user()->id])
->groupBy('report_date')
->orderBy('report_date', 'desc');

laravel filter only nested condition

I want to filter ONLY nested values in dealTransactions.
In plain English, Merchant wants only dealTransactions have provided dates with Deals.
I tried something like below but it does not work.
dates = ['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-05'];
$merchant = Merchant::with(['deals.dealTransactions'])->where('slug', $slug)
->whereHas('deals.dealTransactions', function($query) use ($dates) {
foreach($dates as $date) {
$query->where('date', '=', $date);
}
})
->first();
deal_transactions table
id, deal_id, date
deals table
id, merchant_id,
merchants table
id, many columns for merchant
Thank you
You should be able to do this with a eager load constraint on the nested relationship:
$merchant = Merchant::where('slug', $slug)
->with(['deals.dealTransactions' => function ($query) use ($dates) {
$query->whereIn('date', $dates);
}])->first();
If I understood correctly your schema, this might help:
// Here you define the scope that will be used to select & eager load.
$transactionsScope = function ($q) use ($dates) {
return $q->whereIn('date', $dates);
};
// All merchant of slug in/with that transaction's scope.
$merchant = Merchant::where('slug', $slug)
->whereHas('deals', function ($q) use ($transactionsScope) {
return $q->whereHas('dealTransactions', $transactionsScope);
})
->with(['deals' => function ($q) use ($transactionsScope) {
return $q->with('dealTransactions', $transactionsScope);
}])
->firstOrFail();

How use with() when also joining a table

I have the following tables (with only relevant fields):
devices
id
name
created_at
updated_at
device_reports
id
device_id
location
created_at
updated_at
I have a report with a number of filters on it that is already working, so I want to stick with the eloquent way of doing things. Here is Controller function:
public function devices(Request $request)
{
$devicesQuery = Device::with(['latestReport']);
if ($request->ajax())
{
if($request->input('start') && $request->input('start')!='')
{
$start_date = date('Y-m-d', strtotime($request->input('start')));
$end_date = date('Y-m-d', strtotime($request->input('end')));
$devicesQuery = $devicesQuery->lastReportBetween($start_date,$end_date);
}
$devices = $devicesQuery->paginate(10);
return Response::json(View::make('devices/table', array('devices' => $devices))->render());
}
}
The model's latestReport is defined as:
public function latestReport()
{
return $this->hasOne('App\Models\DeviceReport')->latest();
}
The model's function lastReportBetween is defined as:
public function scopeLastReportBetween($query, $start, $end)
{
$query = $query->join('device_reports AS dr', 'dr.device_id', '=', 'devices.id');
$query = $query->where('dr.id', '=', DB::raw('(SELECT max(dr2.id) FROM device_reports AS dr2 WHERE dr2.device_id = devices.id)'));
$query = $query->where(DB::raw("(IFNULL(dr.gps_time, dr.created_at))"), '>=', DB::raw("STR_TO_DATE('".$start."', '%Y-%m-%d')"));
$query = $query->where(DB::raw("(IFNULL(dr.gps_time, dr.created_at))"), '<=', DB::raw("STR_TO_DATE('".$end."', '%Y-%m-%d')"));
return $query;
}
When running the above with a start/end date selected, I get the correct records returned, but I don't get anything returned in "latestReport", but when I run the page without the date filters in place, it correctly returns the device information and the most recent report record in the latestReport class variable.
Can anyone help me understand how to change this code such that I do get the latestReport back when I also call the lastReportBetween function?
I figured out my problem. I should have been using "whereHas()" instead of manual joins and whatnot.
public function scopeLastReportBetween($query, $start, $end)
{
return $query->whereHas('latestReport', function($reportsQuery) use ($start, $end)
{
$reportsQuery->whereBetween('created_at', [$start, $end])
->where('device_reports.id', '=', DB::raw('(SELECT max(dr2.id) FROM device_reports AS dr2 WHERE dr2.device_id = device_reports.device_id)'));
});
}

Laravel compare between date field and date now

I am trying to compare between date field that saved to my database and current date!
The circle is:
admin will add a new career with deadline date
when someone fill the application he/she will see the available jobs only in drop down list ( that its deadline date less than the current date )
so this is the Jobs model
protected $fillable = ['job_name','job_req', 'expire'];
this is jobs migrations
public function up()
{
Schema::create('jobs', function(Blueprint $table)
{
$table->increments('id');
$table->string('job_name');
$table->string('job_req');
$table->date('expire');
$table->timestamps();
});
}
public function down()
{
Schema::drop('jobs');
}
this is the ApplicationController.php
public function create()
{
$dt = Carbon::now()->toDateString();
$jobs = Jobs::get()->where('$dt', '<', 'expire');
return view('post.create',compact('jobs'));
}
Now when i open application form it doesn't returns any job title, but when i remove where clause from the controller it works well!
change
$jobs = Jobs::get()->where('$dt', '<', 'expire');
to
$jobs = Jobs::where('expire', '>', $dt)->get();
->get() will do query instantly, you must use ->where() before it.
Use ->where after ->get(), you will call this function
http://laravel.com/api/5.1/Illuminate/Database/Eloquent/Collection.html#method_where

Categories