I am having a really tough time figuring out another approach to do search querys on my site. At the moment i have search critierias for "Min size, Max size, City, street, Min. price, Max. price.
So i have these queries (build using Laravel standard):
if (!empty($by) && empty($adresse) && empty($minstor) && empty($maxstor))
{
$users = User::where('pris', '<', $maxpris)->where('pris', '>', $minpris)->where('by', '=', $by)->orderBy('created_at', 'DESC')->get();
}
elseif (!empty($by) && !empty($adresse) && empty($minstor) && empty($maxstor))
{
$users = User::where('pris', '<', $maxpris)->where('pris', '>', $minpris)->where('by', '=', $by)->where('adresse', '=', $adresse)->orderBy('created_at', 'DESC')->get();
}
elseif (empty($by) && !empty($adresse) empty($minstor) && empty($maxstor))
{
$users = User::where('pris', '<', $maxpris)->where('pris', '>', $minpris)->where('adresse', '=', $adresse)->orderBy('created_at', 'DESC')->get();
}
else
{
$users = User::where('pris', '<', $maxpris)->where('pris', '>', $minpris)->orderBy('created_at', 'DESC')->get();
}
All of this simply for the user being able to search for the for the critirias above, but if i want to add several more feautures, i can just imagine how many different if functions i will need to run in order to get all the specific inputs etc. It will evovle eksponentially really quick.
How can i get around this problem without having to create hundreds of different if else statements in order to return the correct query?
You could set up an array of your filters with their corresponding operator. Then iterate over the filters that were passed and running the them (This hasn't been tested but should get you headed in the right direction):
$available_queries = [
['input' => 'maxpris', 'operator' => '<', 'field' => 'pris'],
['input' => 'minpris', 'operator' => '>', 'field' => 'pris'],
['input' => 'by', 'operator' => '=', 'field' => 'by'],
['input' => 'adresse', 'operator' => '=', 'field' => 'addresse'],
]
$query = User::orderBy('created_at', 'DESC');
foreach($available_queries as $filter){
if(request()->input($filter['input'])){
$query = $query->where(
$filter['field'],
$filter['operator'],
request()->input($filter['input'])
);
}
}
$users = $query->get();
EDIT: I found an error in my original script. Updated to fix the error and make more readable.
You can to do like this
$q = User::query();
if (\Input::has('name')) {
$q->where('name', \Input::get('name'));
}
if (\Input::has('address')) {
$q->where('address', \Input::get('address'));
}
...
You can iterate it in loop like this,
foreach($request->all() as $req_field => $req_data) {
if (\Input::has($req_field)) {
$q->where($req_field, \Input::get($req_field));
}
}
p.s. or you can iterate it in scope ...
then
$items = $q->orderBy('id', 'desc')->get();
Related
I am trying to increase the speed of my Laravel 5.4 sql query by using joins, which I've never used before. I currently have the query working and returning results, my issue is that I get like each results around 8 times. Ex: I get the same 2001 Chevrolet Silverado 8 times in my array. If anybody could help me out I would really appreciate it. Thanks
My query + collection:
$tmp = DB::table('inventories'
)->join(
'vehicles', 'vehicles.id', '=', 'inventories.id'
)->join(
'vimages', 'vimages.vehicle_id', '=', 'inventories.id'
)->where(
'inventories.dealer_id', '=', $dealer_id
)->where(
'inventories.is_active', '=', 1
)->where(
'inventories.is_deleted','=', 0
)->select(
'inventories.stock_number','inventories.vehicle_id','vehicles.year','vehicles.make','vehicles.model','vehicles.vin','inventories.vehicle_status',
'inventories.cost','inventories.search_meta','vimages.name'
);
$data = collect();
$pmt = $tmp->get();
// return json_encode( $pmt );
// logger( sprintf('# of rows returned: %s', $pmt->count() ) );
$pmt->each( function($row) use(&$data) {
// logger( sprintf('Row : %s', $row->toJson() ));
$data->push( array(
'stock_number' => $row->stock_number,
'vehicle_id' => $row->vehicle_id,
'year' => $row->year,
'make' => $row->make,
'model' => $row->model,
// 'trim' => $row->trim,
'vin' => $row->vin,
'status' => $row->vehicle_status,
// 'purchase_price' => $row->purchase_price,
'cost' => $row->cost,
// 'retail_price' => $row->retail_price,
'search_meta' => $row->search_meta,
// 'images' => $row->getFirstImage()
'images' => $row->name
// 'interior_color' => $row->vehicle()->first()->interior_color,
// 'exterior_color' => $row->vehicle()->first()->exterior_color,
// 'firstImg' => $row->getFirstImage()
// 'images' => Vimage::select('vehicle_id','name'
// )->where(
// 'dealer_id', '=', $row->dealer_id
// )->where(
// 'vehicle_id', '=', $row->vehicle_id
// )->limit(1)->get()
));
});
Example of my array:
https://i.imgur.com/FOphST8.png
I don't see your db table but I think there is problem in first join statment:
you should use
->join('vehicles', 'vehicles.id', '=', 'inventories.vehicle_id' )
instead of
->join('vehicles', 'vehicles.id', '=', 'inventories.id' )
also second join should be like
->join('vimages', 'vimages.vehicle_id', '=', 'vehicles.id')
instead of
->join('vimages', 'vimages.vehicle_id', '=', 'inventories.id')
It sounds trivial but this should work:
$tmp = DB::table('inventories'
)->join(
'vehicles', 'vehicles.id', '=', 'inventories.id'
)->join(
'vimages', 'vimages.vehicle_id', '=', 'inventories.id'
)->where(
'inventories.dealer_id', '=', $dealer_id
)->where(
'inventories.is_active', '=', 1
)->where(
'inventories.is_deleted','=', 0
)->selectRaw("DISTINCT inventories.stock_number, inventories.vehicle_id,
vehicles.year, vehicles.make, vehicles.model, vehicles.vin,
inventories.vehicle_status, inventories.cost,
inventories.search_meta, vimages.name"
);
Update: forgot to delete the single quotes in selectRaw
Figured it thanks to #Devon. Added another where statement to query to only get first image.
Thanks
)->where('vimages.sequence','=', 0
I am having some trouble in Laravel using the query builder to select users based on two where clauses.
The first where clause would contain multiple where statements to select a user based on some conditions. If this fails in the OR part I would like to check simply if the user ID is in the array.
Would be grateful for some advice on how I could achieve this.
Thanks.
$rs = DB::table('tblUser')
->select('name')
->where(function($q) {
$q->where(function($q){
$q->where('fid', '=', $this->argument('fid'))
->where('type', '<', 10)
})
->orWhereIn('id', $userIdSArray);
})
->get();
$userIdSArray = [ '2', '4', '5' ];
$rs = DB::table( 'Users' )
->select( 'name' )
->where( function ( $q ) use ( $userIdSArray ) {
$q->where( function ( $q ) {
$q->where( 'fid', '=', $this->argument( 'fid' ) )
->where( 'type', '<', 10 );
})
->orWhereIn( 'id', $userIdSArray );
})
->get();
I think you need to pass $userIdSArray in Query builder . And You also forgot (;) after [->where( 'type', '<', 10 )]
i have this
public function deals(){
$matchThese = [ 'suspended' => 0, 'status' => 1, 'approved' => 1 ];
$deals = ListsDeals::where( $matchThese )->orderBy( 'start_date' )->get();
$list = DB::table( 'lists' )
->join( 'list_has_deals', 'lists.id', '=', 'list_has_deals.list_id' )
->where( 'list_has_deals.deal_id', '=', 12)
->select( 'lists.id' )
->get();
$categories = DB::table( 'lists_categories' )
->join( 'list_has_categories', 'lists_categories.id', '=', 'list_has_categories.category_id' )
->where( 'list_has_categories.list_id', '=', $list[0]->id )
->select( 'lists_categories.title' )
->get();
return view( "deals" )
->with( "deals", $deals )
->with( "categories", $categories );
}
I want to obtain the value of title for the categories in lists, but first i need to obtain the deals for the lists in less words
I have
Deals - Lists - lists_has_deals
Categories - Lists - lists_has_deals
Both are belongsToMany, i want obtain in the deals the categories belonging to the list that is associated with the offer.
In my example that works fine but the 12 need to be a foreach of the $deals not be number static, thanks for the help.
Try using a has many through or intermediate pivot table on lists_has_deals. If I'm understanding your question, lists should have the necessary reference to both deals and categories.
https://laravel.com/docs/5.4/eloquent-relationships#has-many-through
https://laravel.com/docs/5.4/eloquent-relationships#many-to-many
specifically withPivot()
NOTE Please do not suggest using Eloquent, this is specifically for the Laravel query builder.
For performance reasons we are using Query Builder to retrieve results from a table:
DB::table('posts')->get();
If we then want to join a relation onto that query:
DB:table('posts')
->leftJoin('comments', 'posts.id', '=', 'comments.post_id')
->get();
The results are merged into the array of each post:
[
'id' => 1,
'title' => 'My Blog Post',
'content' => '<h1>This is a post</h1><p>hello world</p>',
'post_author' => 'Billy',
'comment' => 'This is a comment',
'comment_author' => 'Andrew',
]
How can we have the joined results placed into a nested array? Such as:
[
'id' => 1,
'title' => 'My Blog Post',
'content' => '<h1>This is a post</h1><p>hello world</p>',
'post_author' => 'Billy',
'comment' => [
'id' => 22,
'comment' => 'This is a comment',
'comment_author' => 'Andrew',
],
]
Dont think its doable out of the box without Eloquent.
You can go the primitive route:
$results = DB:table('posts')
->leftJoin('comments', 'posts.id', '=', 'comments.post_id')
->select('posts.*', 'comments.*', 'comments.id as comments_id')
->get();
foreach($results as &$result)
{
$result['comment'] = [
'id' => $result['comment_id'],
'comment' => $result['comment'],
'comment_author' => $result['comment_author']
];
unset($result['comment_author'], $result['comment_id']);
}
Since you work with DB facade and not Eloquent, and cannot use built-in with() method, you have to implement it yourself:
$posts = DB::table('posts')->get()->toArray();
$comments = DB::table('comments')->get()->toArray();
foreach($posts as &$post)
{
$post->comments = array_filter($comments, function($comment) use ($post) {
return $comment->post_id === $post->id;
});
}
return $posts;
If you want to get rid of post_id for comments entries, you can do:
$posts = DB::table('posts')->get()->toArray();
$comments = DB::table('comments')->get()->toArray();
foreach($posts as &$post)
{
$comments = array_filter($comments, function($comment) use ($post) {
return $comment->post_id === $post->id;
});
$post->comments = array_map(function ($comment) {
unset($comment->id);
return $comment;
}, $comments);
}
return $posts;
(I guess the runtime would be similar to with(), since after-all MySql does not provide this functionality out-of-the-box).
Here some new information:
$data= $DB->select("select posts.*,comments from posts left join comments on posts.id = comments.post_id");
I am not sure it is work or not but you can try
You can try with this
$data= $DB->select("select *,(select json_agg(datas) from (select * from comments where posts.id=comments.post_id) as datas) as comments from posts;");
But you may need to decode at comments as well
For example I have the following query which updates a new row:
$query->where('email', '=', $user->email)->where('card_uid', '=', $k)
->update( array('email' => $user->email, 'card_uid' => $k, 'have_quantity' => ($card->have_quantity+$v)) );
I'd like to retrieve the updated (or inserted) row. I tried the following but it doesn't work:
$row = $query->where('email', '=', $user->email)->where('card_uid', '=', $k)
->update( array('email' => $user->email, 'card_uid' => $k, 'have_quantity' => ($card->have_quantity+$v)) )
->get();
How can I retrieve the row I am updating or inserting easily?
You can try using the same query builder instance for the update first and then run the select query. (You can't do it the way you tried because update() returns the number of affected rows)
$query->where('email', '=', $user->email)->where('card_uid', '=', $k);
$query->update(array('email' => $user->email, 'card_uid' => $k, 'have_quantity' => ($card->have_quantity+$v)))
$row = $query->get();