I can't find informations about: how make complex select from cache Laravel 5.
I have query :
$companys = Company::with(['comments' => function ($query) {
$query->where('status', '=', 'done');
}])->withCount('comments')->has('comments')->inRandomOrder()->paginate(8);
I need caching this query.
I want firstly caching all companys with commets and after make query to cache for get random companys with count comments and pagination.
Somethink like this:
$cache_companys = Cache::remember('companys', 30, function () {
return Company::with('comments')->get();
});
and after from $cache_companys get my companys for pagination.
I tryed make:
$companys = Cache::remember('companys', 30, function () {
return Company::with(['comments' => function ($query) {
$query->where('status', '=', 'done');
}])->withCount('comments')->has('comments')->inRandomOrder()->paginate(8);
});
but in this case at every pages of paginations was same companys.
Help me please.
Thank you.
solution of my question:
$currentPage = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$companys = Cache::remember('companys-'.$currentPage, 30, function () {
return Company::with(['comments' => function ($query) {
$query->where('status', '=', 'done');
}])->withCount('comments')->has('comments')->inRandomOrder()->paginate(8);
});
Related
I want to retrieve all the offices ( with the desks eager loaded) but I only want offices where the user possess all the desks in the office
I have the following models and relationships between them :
I came up with the following query which seems to almost work :
<?php
Office::query()
->whereHas('desks', function ($query) {
$query->whereHas('possessedDesks', function ($query) {
$query->where('user_id', auth()->id);
});
})
->with(['desks'])
->get();
The current query seems to return a result where if a user own a single desk in the office then the office is returned in the query. Am I missing something ? Is there a way to be more strict in the whereHas to have some kind of and instead of a or
Thanks in advance for your help ;)
Edit :
Thanks to Tim Lewis's comment I tried this with not more result :
<?php
Office::query()
->withCount('desks')
->whereHas('desks', function ($query) {
$query
->whereHas('possessedDesks', function ($query) {
$query->where('user_id', auth()->id);
})
->has('possessedDesks', '=', 'desks_count');
})
->with(['desks'])
->get();
Edit 2 :
I managed to get exactly what I need, outside of an Eloquent query. The problem is still persist since I need it to be in an Eloquent query because I need this for a query string request (Search engine).
<?php
$offices = Office::query()
->with(['desks'])
->get();
$possessedDeskIds = auth()->user->with('possessedDesks.desk')->possessedDesks()->get()->pluck('desk.id');
$fullyOwnedOffices = [];
foreach($offices as $office) {
$officeDeskIds = $office->desks()->pluck('id');
$atLeastOneDeskIsNotPossessed = false;
foreach($officeDeskIds as $officeDesk) {
if ($possessedDeskIds->doesntContain($officeDesk)) {
$atLeastOneAromaIsNotPossessed = true;
break;
}
}
if (!$atLeastOneDeskIsNotPossessed) {
$fullyOwnedOffices[] = $office;
}
}
Edit 3 :
Ok, With the previous edit and the need to have some kind of one line query (for the query string of a search engine) I simplified the request since the nested whereHas where hard to make sense of.
It's not the prettiest way to do it, It add more query for the process, but with the code from the Edit2 I can generate an array of Ids of the Office where all the Desk are possessed by the user. With that I can just say that when this option is required in the search engine, I just select the ones my algorithm above gave me and no more logic in the query.
If some genius manage to find a way to optimize this query to add the logic back inside of it, I'll take it but for now it works as expected.
Thanks Tim for your help
<?php
class SearchEngineController extends Controller
{
public function index(Request $request) {
$officesWithAllDesksPossessed = collect([]);
if ($request->has('with_possessed_desks') && $request->input('with_possessed_desks')) {
$publicOffices = Office::query()
->isPublic()
->with(['desks'])
->get();
$possessedDeskIds = currentUser()
->possessedDesks()
->with('desk')
->get()
->pluck('desk.id');
foreach($publicOffices as $office) {
$publicOfficesDeskIds = $office->desks()->pluck('id');
$atLeastOneDeskIsNotPossessed = false;
foreach($publicOfficesDeskIds as $officeDesk) {
if ($possessedDeskIds->doesntContain($officeDesk)) {
$atLeastOneDeskIsNotPossessed = true;
break;
}
}
if (!$atLeastOneDeskIsNotPossessed) {
$officesWithAllDesksPossessed->push($office);
}
}
$officesWithAllDesksPossessed = $officesWithAllDesksPossessed->pluck('id');
}
return Inertia::render('Discover', [
'offices'=> OfficeResource::collection(
Office::query()
->isPublic()
->with(['desks'])
->when($request->input('search'), function ($query, $search) {
$query->where('name', 'like', "%{$search}%");
})
->when($request->input('with_possessed_desks'), function ($query, $active) use($officesWithAllDesksPossessed) {
if ($active === 'true') {
$query->whereIn('id', $officesWithAllDesksPossessed);
}
})
->paginate(10)
->withQueryString()
),
'filters' => $request->only(['search', 'with_possessed_desks']),
]);
}
}
I have 3 tables products, prices, cats.
I need to filter product by cats and sort by price but I have a problem:
this code work very well but needs pagination.
$products = Product::with('photo', 'price', 'brand')
->whereHas('cats', function ($q) use ($cat) {
$q->where('cat_id', $cat->id);
})
->get()
->sortByDesc(function($query) {
return $query->price->price;
});
at first I did it like this:
$products = Product::with('photo', 'price', 'brand')
->whereHas('cats', function ($q) use ($cat) {
$q->where('cat_id', $cat->id);
})
->paginate($page)
->sortByDesc(function ($query) {
return $query->price->price;
});
but links() did not work.
After i did it like this:
$products = Product::with('photo', 'price', 'brand')
->whereHas('cats', function ($q) use ($cat){
$q->where('cat_id', $cat->id);
})
->paginate($page);
$products->setCollection(
$products->sortBy(function ($query) {
return $query->price->id;
})
);
but sortBy does not work.
so I can't use orderBy() by join prices table
because when I do it I can show all products and I can't filter product by categories
my mind does not work, if someone can to help me, I will be very grateful
I believe you can also do:
Product::join('price', 'price.id', '=', 'photo.price_id')
->orderBy('price.price', 'asc')
->select('photo.*')
->paginate(10);
I am making an app that filters products
I want to add this query chunk to my $products = $products-> newQuery();
I'm using $products = $products-> newQuery(); Because I am querying with filters. Example:
$products = $products->newQuery();
if ($request->has('brand') && !empty($brand)) {
$products->where('brand', '=', $brand);
}
if ($request->has('size') && !empty($size)) {
$products->whereHas('stocks', function($query) use ($size) {
$query->where('size', '=', $size);
});
}
I want to add this query
$best_sellers = OrderItem::select('product_id')->groupBy('product_id')->orderByRaw('SUM(quantity) DESC')->limit(2)->get();
I have previously used it in another method and it works but I don't know how to integrate it
I tried:
$products->whereHas('order_items', function($query) {
$query->select('product_id')->groupBy('product_id')->orderByRaw('SUM(quantity) DESC');
});
But it hasn't worked
Any idea? thanks
Updated with Error:
you need to use with() to add relationship data whereHas() it just for filter it does not add new key
example
$products->with(['order_items'=> function ($q) {
$q->select('product_id')->groupBy('product_id')->orderByRaw('SUM(quantity) DESC')->limit(2)->get();
}]);
Follow is my query which is working perfectly fine, it is giving me the expected result, but i am not happy with the way i have broken down the query in 3 pieces.
How can i combine this query like without breaking it down in pieces ?
$assignedMenusQuery = Branch::with(['menus' => function($query) {
$query->where('menus.status', true);
}])
->where('id', $branch->id)
->first();
if($assignedMenusQuery)
{
$assignedMenus = $assignedMenusQuery->menus->pluck('id')->toArray();
}
$assignedButSharedMenusQuery = Branch::with(['menus' => function($query) {
$query->where('menus.shared', true)
->where('menus.status', true);
}])
->whereNotIn('id', [$branch->id])
->first();
if($assignedButSharedMenusQuery)
{
$assignedButSharedMenus = $assignedButSharedMenusQuery->menus->pluck('id')->toArray();
}
$assignedButNotSharedMenusQuery = Branch::with(['menus' => function($query) {
$query->where('menus.shared', false)
->where('menus.status', true);
}])
->whereNotIn('id', [$branch->id])
->first();
if($assignedButNotSharedMenusQuery)
{
$assignedButNotSharedMenus = $assignedButNotSharedMenusQuery->menus->pluck('id')->toArray();
}
$menus = Menu::whereIn('id', array_merge($assignedMenus, $assignedButSharedMenus))->whereNotIn('id', $assignedButNotSharedMenus)->get();
Here what you can do this make a seperate function which accepts a parameter for shared & status. And other param for whereNotIn. And in that function you can use the when method and based on that you have to query in database.
Laravel Conditional Clauses
Here is how i did it, in case if someone needs it in future
$products = Product::whereNotIn('id', function($query) use($menu) {
$query->from('menu_product')
->select('menu_product.product_id');
})
->orWhereIn('id', function($query) {
$query->from('menu_product')
->select('menu_product.product_id')
->where('products.shared', true);
})
->orWhereIn('id', function($query) use($menu) {
$query->from('menu_product')
->select('menu_product.product_id')
->where('menu_product.menu_id', $menu->id);
})
->get();
I am getting data from products table, i have use paginate in datatable which shows only 50 records first time, and when pager update to 200 rows it takes 12 to 13sec. Here is my Code. Thanks in Advance
$query = Product::query();
$query->with('def_or_last_supplier','units','prouctImages','productType',
'productBrand','productSubCategory',
'supplier_products','productCategory')
->where('status',1)->orderBy('refrence_no', 'DESC');
if($request->default_supplier != '')
{
$supplier_query = $request->default_supplier;
$query = $query->whereIn('id', SupplierProducts::select('product_id')->where('supplier_id',$supplier_query)->pluck('product_id'));
}
if($request->prod_type != '')
{
$query->where('type_id', $request->prod_type)->where('status',1)->orderBy('refrence_no', 'DESC');
}
if($request->prod_category != '')
{
$query->where('category_id', $request->prod_category)->where('status',1)->orderBy('refrence_no', 'DESC');
}
if($request->filter != '')
{
if($request->filter == 'stock')
{
$query = $query->whereIn('id',WarehouseProduct::select('product_id')->where('current_quantity','>',0.005)->pluck('product_id'));
}
elseif($request->filter == 'reorder')
{
$query->where('min_stock','>',0);
}
}
Your query isn't that big but I think maybe result data size is a bit big
so what you can do is:
1: in my experience is to try to select your relations fields too you can do that like so
Source
Product::with('def_or_last_supplier',
'units:id,created_at,updated_at', // Just add :field_1,field_2,another_field
'prouctImages:id,field_1,field_2'
....
)
2: I suggest you to take advantage of lazy loading. if it's possible don't eager load all your relations at once load them where it's needed
Source
$products = Product::get()
In blade or somewhere in application
under a special condition I need to access to my relation, I can easily do that by
$products->load('my_relation_name')
3: I see a lot of orderyBy clauses in your code, what you can do is to index the fields that are searchable or needs to be ordered. it can be done by adding ->index() in your migration file
Source
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('refrence_no')->index();
$table->timestamps();
});
}
4: and finally you can always try to cache your queries to prevent unnecessary queries to database, this is how cache works
source
$products = Cache::remember('cache_name', $how_long_in_seconds, function () {
return Product::get();
});
And finally here is the eloquent way of your query
$query = \Cache::remember(json_encode($request->toArray()), 300, function () use ($request) {
return Product::with('def_or_last_supplier',
'units',
'prouctImages',
'productType',
'productBrand',
'productSubCategory',
'supplier_products',
'productCategory'
)
->where('status', 1)
->orderByDesc('refrence_no')
->when($request->filled('default_supplier'), function (Builder $query) use ($request) {
$productIds = SupplierProducts::select('product_id')->where('supplier_id', $request->input('default_supplier'))->pluck('product_id');
$query->whereIn('id', $productIds);
})->when($request->filled('prod_type'), function (Builder $query) use ($request) {
$query->where('type_id', $request->input('prod_type'))->where('status', 1)->orderByDesc('refrence_no');
})->when($request->filled('prod_category'), function (Builder $query) use ($request) {
$query->where('category_id', $request->input('prod_category'))->where('status', 1)->orderByDesc('refrence_no');
})->when($request->filled('filter'), function (Builder $query) use ($request) {
$query->when('stock' === $request->input('filter'), function (Builder $query) {
$query->whereIn('id', WarehouseProduct::select('product_id')->where('current_quantity', '>', 0.005)->pluck('product_id'));
})->when('reorder' === $request->input('filter'), function (Builder $query) {
$query->where('min_stock', '>', 0);
});
})->get();
});