Laravel slow query for 30000 db row - laravel

I have 32000 occurrence of transactions in my db, this query takes too long
about 10 sec or more,
how can i optimize please
$data = DB::table('transactions')
->when($merchantId, function($query) use($merchantId) {
return $query->where('user_id', $merchantId);
})
->whereBetween('created_at', [
Carbon::now()->startOfYear(),
Carbon::now()->endOfYear(),
])->when($app, function($query) use($app) {
return $query->where('application_id', $app);
})
->where(function ($query) {
$query->where('status', 'CANCELLED')
->orWhere('status', 'FAILED');
})
->selectRaw("count(*) as nombre, extract($period from transactions.created_at) as $period")
->groupBy("$period")
->pluck('nombre', "$period");

Related

Multiple Where Clause in Laravel not working as needed

I am trying to get all the expired listings from the db. the table has three fields for the expiry date, to_date_1, to_date_2, to_date_3.
date 2&3 may have a null value but date 1 always has a value. If date 3 is not null I want the query to compare with date 3 and skip date1 &2. if date 3 is null, the query should compare with date 2, otherwise date 1 will be the expiry date. here is my query.
$query = Listing::query()
->where('vendor_id', $vendor->id)
->where('is_deleted', 0)->where('is_published', 1)->where('is_approved', 1)
->where(function ($q) {
return $q->WhereNotNull('to_date_3')->Where('to_date_3', '<', \Carbon\Carbon::now()->format('Y-m-d'));
})
->where(function ($q) {
return $q->WhereNotNull('to_date_2')->Where('to_date_2', '<', \Carbon\Carbon::now()->format('Y-m-d'));
})
->where(function ($q) {
return $q->orWhere('to_date_1', '<', \Carbon\Carbon::now()->format('Y-m-d'));
})
->orderBy('created_at', 'desc');
$listings = $query->paginate(10);
Here is a sample data:
id
from_date_1
to_date_1
from_date_2
to_date_2
from_date_3
to_date_3
1
2021-06-10
2021-08-15
2021-08-16
2021-08-31
2021-09-01
2021-09-15
2
2021-06-25
2021-08-10
2021-08-11
2021-08-22
NULL
NULL
3
2021-06-25
2021-08-20
NULL
NULL
NULL
NULL
if today date is: 21-08-2021, the result should be record: 1 & 2
As Pavlo said group your query inside a where
$query = Listing::query()
->where(function ($query) { // Wrap you code inside a where
$query->where('vendor_id', $vendor->id)
->where('is_deleted', 0)->where('is_published', 1)->where('is_approved', 1)
->where(function ($q) {
return $q->WhereNotNull('to_date_3')->Where('to_date_3', '<', Carbon::now()->format('Y-m-d'));
})
->where(function ($q) {
return $q->WhereNotNull('to_date_2')->Where('to_date_2', '<', Carbon::now()->format('Y-m-d'));
})
->where(function ($q) {
return $q->orWhere('to_date_1', '<', Carbon::now()->format('Y-m-d'));
});
})
->orderBy('created_at', 'desc');
$listings = $query->paginate(10);
Try use orWhere
->where('is_deleted', 0)->where('is_published', 1)->where('is_approved', 1)
->where(function ($q) {
return $q->WhereNotNull('to_date_3')->Where('to_date_3', '<', \Carbon\Carbon::now()->format('Y-m-d'));
})
->orWhere(function ($q) {
return $q->WhereNotNull('to_date_2')->Where('to_date_2', '<', \Carbon\Carbon::now()->format('Y-m-d'));
})
->orWhere(function ($q) {
return $q->orWhere('to_date_1', '<', \Carbon\Carbon::now()->format('Y-m-d'));
})
More about parameters grouping
UPDATING (where -> orWhere -> orWhere give you your sql)

Laravel with() Eloquent as variable or another array

I have this Eloquent query that want to display the orders by day, yesterday, week, last week, this month, last month, this year, last year and this is my code however, it does not work or do have any idea to re do the code. In my sample code I do not know how to put into another each with() query with different parameters. Please help.
$product_orders = Product::where('status', 'active')
->with(['order_detail' => function($query) {
$query->with('order');
$query->where('created_at', '>=', today());
}])
->with(['order_detail' => function($query) {
$query->with('order');
$query->where('created_at', '>=', Carbon::yesterday());
}])
->with(['order_detail' => function($query) {
$query->with('order');
$query->where('created_at', '>=', [now()->startOfWeek(), now()->endOfWeek()]);
}])
->with(['order_detail' => function($query) {
$query->with('order');
$query->where('created_at', '>=', [now()->subWeek()->startOfWeek(), now()->subWeek()->endOfWeek()]);
}])
->with(['order_detail' => function($query) {
$query->with('order');
$query->whereYear('created_at', '=', now()->year);
$query->whereMonth('created_at', '=', now()->month);
}])
->with(['order_detail' => function($query) {
$fromDate = Carbon::now()->subMonth()->startOfMonth()->toDateString();
$tillDate = Carbon::now()->subMonth()->endOfMonth()->toDateString();
$parse_fromDate = Carbon::parse($fromDate.' 00:00:00');
$parse_tillDate = Carbon::parse($tillDate.' 23:59:59');
$query->with('order');
$query->whereBetween('created_at',[$parse_fromDate,$parse_tillDate]);
}])
->with(['order_detail' => function($query) {
$query->with('order');
$query->whereYear('created_at', '>=', now()->year);
}])
->with(['order_detail' => function($query) {
$last_year = now()->year - 1;
$query->with('order');
$query->whereYear('created_at', '>=', $last_year);
}])
->get();
With this approach, you're essentially overwriting each "with" with the next one in the chain, so that the only thing that is actually executed is the final "with".
What you will need to do is break these into separate queries, with separate result sets, since, at the core you appear to want result from multiple different queries with different criteria.
$todays_orders = Product::where('status', 'active')
->with(['order_detail' => function($query) {
$query->with('order');
$query->where('created_at', '>=', today());
}])
->get();
$yesterdays_orders = Product::where('status', 'active')
->with(['order_detail' => function($query) {
$query->with('order');
$query->where('created_at', '>=', Carbon::yesterday());
}])
->get();
... etc...
Use the query:
$product_orders = Product::where('status', 'active')
->with([ 'order_detail' => function ($query) {
$last_year = now()->year - 1;
$query->whereYear('created_at', '>=', $last_year);
}, 'order_detail.order' ])->get();
$product_orders->each(function (Product $product) {
$product->today_orders = $product->order_detail->where('created_at', '>=', Carbon::today());
$product->today_orders = $product->order_detail->whereBetween('created_at', [ Carbon::yesterday(), Carbon::today() ]);
$product->weeks_orders = $product->order_detail->whereBetween('created_at', [ Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek() ]);
$product->last_weeks_orders = $product->order_detail->whereBetween('created_at', [ Carbon::now()->subWeek()->startOfWeek(), Carbon::now()->subWeek()->endOfWeek() ]);
// and so on
});
Then in your view each product should have properties that were set in the each
I found my own solution by creating it with filter inside the Model
in Controller
$product_orders = Product::where('status', 'active')
->with('order_detail_today', 'order_detail_yesterday', 'order_detail_this_week',
'order_detail_last_week','order_detail_this_month', 'order_detail_last_month',
'order_detail_this_year', 'order_detail_last_year')->get();
in Model
public function order_detail_today()
{
return $this->hasMany('App\Order_detail','reference_number')
->where('order_type', '!=', 'package')
->with('order')
->where('created_at', '>=', today());
}
public function order_detail_yesterday()
{
return $this->hasMany('App\Order_detail','reference_number')
->where('order_type', '!=', 'package')
->with('order')
->where('created_at', '>=', Carbon::yesterday());
}
public function order_detail_this_week()
{
return $this->hasMany('App\Order_detail','reference_number')
->where('order_type', '!=', 'package')
->with('order')
->where('created_at', '>=', [now()->startOfWeek(), now()->endOfWeek()]);
}
public function order_detail_last_week()
{
return $this->hasMany('App\Order_detail','reference_number')
->where('order_type', '!=', 'package')
->with('order')
->where('created_at', '>=', [now()->subWeek()->startOfWeek(), now()->subWeek()->endOfWeek()]);
}
public function order_detail_this_month()
{
return $this->hasMany('App\Order_detail','reference_number')
->where('order_type', '!=', 'package')
->with('order')
->whereYear('created_at', '=', now()->year)
->whereMonth('created_at', '=', now()->month);
}
public function order_detail_last_month()
{
$fromDate = Carbon::now()->subMonth()->startOfMonth()->toDateString();
$tillDate = Carbon::now()->subMonth()->endOfMonth()->toDateString();
$parse_fromDate = Carbon::parse($fromDate.' 00:00:00');
$parse_tillDate = Carbon::parse($tillDate.' 23:59:59');
return $this->hasMany('App\Order_detail','reference_number')
->where('order_type', '!=', 'package')
->with('order')
->whereYear('created_at', '=', now()->year)
->whereBetween('created_at',[$parse_fromDate,$parse_tillDate]);
}
public function order_detail_this_year()
{
return $this->hasMany('App\Order_detail','reference_number')
->where('order_type', '!=', 'package')
->with('order')
->whereYear('created_at', '>=', now()->year);
}
public function order_detail_last_year()
{
$last_year = now()->year - 1;
return $this->hasMany('App\Order_detail','reference_number')
->where('order_type', '!=', 'package')
->with('order')
->whereYear('created_at', '>=', $last_year);
}

Laravel eloquent order by subquery

I have a problem with ordering by columns in subquery (lastname, firstname).
I already tried this code as suggested by other posts:
->with(['customer' => function ($query) {
$query->orderBy("lastname", "asc")
->orderBy("firstname", "asc");
}])
Here my full code, but it doesn't work.
return Membership::forCompany($companyId)
->whereIn('state', ['ATTIVA', 'IN ATTESA DI ESITO', 'DA INVIARE'])
->where(function ($query) {
$query->where('end_date', '>=', Carbon::now()->toDateString())
->orWhereNull('end_date');
})
->with('federation')
->with(['customer' => function ($query) {
$query->orderBy("lastname", "asc")
->orderBy("firstname", "asc");
}]);
Here the relationships:
In customer model I have:
public function memberships() {
return $this->hasMany('App\Models\Membership');
}
In Membership model I have:
public function customer() {
return $this->belongsTo("App\Models\Customer");
}
Try orderBy() with join() like:
$memberships = \DB::table("memberships")
->where("company_id", $companyId)
->where(function ($query) {
$query->where('end_date', '>=', Carbon::now()->toDateString())
->orWhereNull('end_date');
})
->join("customers", "memberships.customer_id", "customers.id")
->select("customers.*", "memberships.*")
->orderBy("customers.lastname", "asc")
->get();
dd($memberships);
Let me know if you are still having the issue. Note, code not tested! so you may need to verify by yourself once.

Orderby Desc in Eloquent, Laravel

I have a query 3 tables are joined together, I want to order the results in Descending order from created_at in messages table, please help. Thank you.
controller:
return new AllChats(Chat::latest('created_at')->whereHas('messages')->with(['messages.users', 'users' =>
function ($query) {
$query->where('id', '!=', Auth::id());
}])->whereHas('users', function ($query) {
$query->where('id', '=', Auth::id());
})->get());
Display the results in desc order but from messages.created_at??
You need to just add the ->orderBy on your created at field in your query.
return new AllChats(Chat::latest('created_at')->whereHas('messages')->with(['messages.users',
'users' => function ($query) {
$query->where('id', '!=', Auth::id());
}])
->orderBy('created_at', 'desc')
->whereHas('users', function ($query) {
$query->where('id', '=', Auth::id());
})->get());
Reference: https://laravel.com/docs/5.7/eloquent
use like this
return new AllChats(Chat::latest('created_at')>>whereHas('messages',function($q){
$q->orderBy('created_at', 'desc');
})->with(['messages.users', 'users' =>
function ($query) {
$query->where('id', '!=', Auth::id());
}])->whereHas('users', function ($query) {
$query->where('id', '=', Auth::id());
})->get());
You can use a modified withCount():
$chats = Chat::withCount(['messages as latest_message' => function($query) {
$query->select(DB::raw('max(created_at)'));
}])
->orderByDesc('latest_message')
[...]
->get();

Laravel query with relationships and conditions

Hi I have 3 tables in DB. Here is my query:
$nav = PageNav::with([
'page' => function($query) {
$query->where('status', 1)
->where(function($query) {
$query->whereNull('publish_up')
->whereNull('publish_down');
})
->orWhere(function ($query) {
$query->where('publish_up', '<', date('Y-m-d H:i:s'))
->where('publish_down', '>', date('Y-m-d H:i:s'));
});
},
'langs' => function ($query) use ($lang) {$query->where('language_code', '=', $lang);},
])
->get();
It generates this queries:
When I loop $nav there are still pages with status = 0. I really don't understand why? Any suggestions?
As with any SQL query or Eloquent query, OR completely separates the conditions, so as soon as you have an orWhere in eloquent, it will match anything that matches before the OR or after the OR.
You can resolve this by using a nested where, or parentheses in SQL, to properly encapsulate the conditions.
$query->where('status', 1)
->whereNested(function($q1) {
$q1->where(function($query) {
$query->whereNull('publish_up')
->whereNull('publish_down');
})
->orWhere(function ($query) {
$query->where('publish_up', '<', date('Y-m-d H:i:s'))
->where('publish_down', '>', date('Y-m-d H:i:s'));
});
});
Ok I found solution. Needed to wrap condition to whereHas
$nav = PageNav::whereHas('page', function ($query) {
$query->where('status', 1)
->whereNested(function($q1) {
$q1->where(function($query) {
$query->whereNull('publish_up')
->whereNull('publish_down');
})
->orWhere(function ($query) {
$query->where('publish_up', '<', date('Y-m-d H:i:s'))
->where('publish_down', '>', date('Y-m-d H:i:s'));
});
});
})
->with([
'page',
'langs' => function ($query) use ($lang) {
$query->where('language_code', '=', $lang);
}
])
->get();

Resources