So I'm building an ECommerce site using Laravel/MySQL, the product related tables I have are as follows: 'products', 'attributes', 'taxonomies' and 'tags'. When a user types a keyword to search for product, I want to search all 4 tables with one query to get the desired products, then I want to use Laravel paginate function to paginate the result, now how do I make it done in one query? Maybe some joins involved?
Here it is, the relationship of my database tables, as for my models, it is defined like this:
class Product extends Eloquent {
...
public function taxonomies() {
return $this->belongsToMany('Taxonomy', 'product_taxonomy', 'product_id', 'taxonomy_id');
}
...
// Same goes for attributes and labels
public function reviews() {
return $this->hasMany('Review', 'product_id');
}
}
Maybe you want something like this:
$products = Product::where('name', 'LIKE ', '%' . $keyword . '%');
$products = $products->orWhereHas('attributes',
function ($query) use ($keyword) {
$query->where('name', 'LIKE ', '%' . $keyword . '%');
}
);
$products = $products->orWhereHas('taxonomies',
function ($query) use ($keyword) {
$query->where('name', 'LIKE ', '%' . $keyword . '%');
}
);
$products = $products->orWhereHas('tags',
function ($query) use ($keyword) {
$query->where('name', 'LIKE ', '%' . $keyword . '%');
}
);
$products = $products->paginate(10);
Now you look in product name and in names of your relations (tags, taxonomies and attributes) and paginate 10 products.
You can try like this
$data = DB::table('products')
->join('attributes', 'products.attributes_id', '=', 'attributes.id')
->join('taxonomies', 'products.taxonomies_id', '=', 'taxonomies.id')
->join('tags', 'host_vulnerabilities.tags_id', '=', 'tags.id')
->where('products.id', '=', $id)
->select('products.id', 'attributes.name') //all required fields
->paginate(15);
I have just added sample example. Please update code as per your requirement
Use UNION for this,
SELECT product_id, product name FROM Products WHERE keyword = 'my_keyword' UNION
SELECT product_id, product name FROM Attributes WHERE keyword = 'my_keyword' UNION
..... Same for other tables
Moreover it will filter out repeated results as UNION works as UNION DISTINCT. But if you provide us with a schema or some db structure, can provide a better solution.
For Laravel, this may work you can create a view and query the view instead of the actual tables, or create your Paginator manually:
$page = Input::get('page', 1);
$paginate = 10;
$w1 = 'my_keyword';
$first = DB::table('products')->where('attribute', 'like', '"%'.$w1.'%"');
$second = DB::table('attributes')->where('attribute', 'like', '"%'.$w1.'%"');
$third = DB::table('taxonomies')->where('attribute', 'like', '"%'.$w1.'%"');
$fourth = DB::table('tags')->where('attribute', 'like', '"%'.$w1.'%"');
$union1 = $first->union($second);
$union2 = $third->union($union1);
$union3 = $fourth->union($union2);
$union3->get();
$slice = array_slice($union3, $paginate * ($page - 1), $paginate);
$result = Paginator::make($slice, count($union3), $paginate);
return View::make('yourView',compact('result'));
Related
I'm using the Laravel Eloquent query builder and i want to have advance queries inside when clause
my eloquent :
bank::where('shop_id', $shopId)
->when(($search != ""), function ($query) use ($search) {
return $query->orWhere('bank_name', 'like', '%'.$search.'%')
->orWhere('account_name', 'like', '%'.$search.'%')
->orWhere('account_number', 'like', '%'.$search.'%');
})->toSql();
sql from eloquent :
select * from bank
where shop_id = 1
and bank_name like '%Bank%' or
account_name like '%Bank%' or
account_number like '%Bank%'
sql result that i want:
select * from bank
where shop_id = '1'
and (bank_name like '%Bank%' or
account_name like '%Bank%' or
account_number like '%Bank%')
i can use subquery but its not efficient.
You need to use the closure form of where around the or wheres:
bank::where('shop_id', $shopId)
->when(($search != ""), function ($query) use ($search) {
return $query->where(function ($query) use ($search) {
return $query
->orWhere('bank_name', 'like', '%'.$search.'%')
->orWhere('account_name', 'like', '%'.$search.'%')
->orWhere('account_number', 'like', '%'.$search.'%');
})
})
->toSql();
Here is my code
$search_term = "Hary Kumar";
$filterData = DB::table('signups')->where('name','LIKE',"%{$search_term}%");
If I am not wrong above code will give me result like:
select * from signups where name like "%Hary Kumar%"
But, I am trying to get
select * from signups where name like "%Hary%" or name like "%Kumar%"
You are looking for a simple orWhere()
DB::table('signups')
->where('name', 'LIKE', "%{$first_term}%")
->orWhere('name', 'LIKE', "%{$second_term}%");
I got my answer. Here is the code:
$search_values = explode(" ",$search_term);
DB::table('signups')
->orWhere(function ($query) use($search_values) {
foreach($search_values as $search_value)
$query->orwhere('name', 'like', '%' . $search_value .'%');})
I'm having trouble in querying 2 tables.
Basically I have a 'black_list' table with 2 columns 'user_id' and 'block_id', where 'user_id' is the current user and 'block_id' is the blocked user. The other table is 'users' where there are the information of the registered users.
In my site I have a page where users are searched, my problem is that if id1 blocked id2, when id2 searches id1 it should not be displayed, so in the table 'black_list' I will have these values user_id = 1 and block_list = 2
I've tried so many ways, but I'm not succeeding, can you help me? Excuse my English
public function search(Request $request){
$id= Auth::id();
$query = $request->query('query');
$utentis = DB::table('black_lists')
->join('users', 'users.id', '=', 'users.id')
->where('users.id', '!=', $id)
->where('users.name', 'like', '%' . $query . '%')
->where('black_lists.user_id', '!=', 'users.id')
->orWhere('users.cognome', 'like', '%' . $query . '%')
->where('black_lists.user_id', '!=', 'users.id')
->where('users.id', '!=', $id)
->orWhere('users.username', 'like', '%' . $query . '%')
->where('black_lists.user_id', '!=', 'users.id')
->where('users.id', '!=', $id)
->select('users.id', 'users.name', 'users.fotoProfilo')
->get();
if ($utentis->count() > 0) {
return response()->json($utentis);
}
}
I assume you create a many-to-many relationship between users and black_list is a pivot table.
public function search(Request $request)
{
$id = $request->id;
return User::where('id', $id)
->whereDoesntHave('blocks', function($query) use ($id) {
$query->where('user_id', '!=', $id);
}),
]);
}
UPDATE
// User.php
public function blocks()
{
return $this
->belongsToMany(User::class, 'black_list', 'block_id', 'user_id')
->using(BlackList::class)
->withTimestamps();
}
Notes:
The column names may be in the wrong order because I always mix them. Look at the documentation for more info.
If you created a model for pivot table you need to add ->using(BlackList::class)
If you have BlackList.php, you need to extend it to Pivot rather than Model.
Thanks to both of you for the prompt reply. Unfortunately it returns me null with #gbalduzzi solution. I try to attach a screen of the tables.
The variable $id = Auth::id();
enter image description hereWhen I run the query, it should return me the user profile only if in the black_list table there is no user_id == "user id that blocked me" and block_id == $ id. Thanks again for your help.
Perfect works great, thanks so much for the help
public function search(Request $request)
{
$id= Auth::id();
$query = $request->query('query');
$utentis = User::where('users.id', '!=', $id)
->where(function ($filter) use ($query) {
$filter->where('users.name', 'like', '%' . $query . '%')
->orWhere('users.cognome', 'like', '%' . $query . '%')
->orWhere('users.username', 'like', '%' . $query . '%');
})
->whereDoesntHave('blocks', function ($query) use ($id) {
$query->where('black_lists.block_id','=', $id)
->where('black_lists.user_id','!=', 'users.id');
})
->select('users.id', 'users.name', 'users.fotoProfilo')
->get();
//Log::debug($utentis);
if ($utentis->count() > 0) {
return response()->json($utentis);
}
}
I'm currently working with an Activities table which has Thread and Replies records associated with it. When I try to join the tables, I get a mix and match and both records and it doesn't return individual records, but with records containing both Thread and Reply "body" field. I'm hoping someone can see what I'm trying to do with the code I'm providing:
if (request('name')){
$name = request('name');
$user = User::where('name', $name)->firstOrFail();
$activities = \DB::table('activities')
->leftJoin('threads', function($builder) use ($user){
$builder->on('threads.user_id', '=', 'activities.user_id')
->where('activities.user_id', '=', $user->id)
->where('activities.activity_type', '=', 'App\Thread');
})
->leftJoin('replies', function($builder) use ($user){
$builder->on('replies.user_id', '=', 'activities.user_id')
->where('activities.user_id', '=', $user->id)
->where('activities.activity_type', '=', 'App\Reply');
})
->where('replies.body', 'LIKE', '%' . $search . '%')
->orWhere('threads.title', 'LIKE', '%' . $search . '%')
->orWhere('threads.body', 'LIKE', '%' . $search . '%')
->get()->unique('id');
}
I want to return Threads and Replies separately with all the other fields, as sometimes in my experimentation it has led to the user being null or the body being null and I just don't understand why.
Sometimes it will return a App\Thread in the Activities table that I have created as an App\Reply. I'll admit my knowledge of joins is limited so I'm asking if anyone can please help!
I've got this new query here:
$activities = Activity::with('activity')->whereHas('thread', function ($query) use ($search, $user) {
$query->where('threads.user_id', '=', $user->id)
->where('threads.body', 'LIKE', '%' . $search . '%')
->orWhere('threads.title', 'LIKE', '%' . $search . '%');
})->orWhereHas('reply', function ($query) use ($search, $user) {
$query->where('replies.body', 'LIKE', '%' . $search . '%')
->where('replies.user_id', '=', $user->id);
})->get();
Thank you!
After trying to include the user in the query builder, I just added the user after my ::with clause and got the following query to work:
$activities = Activity::with('activity')->where('user_id', $user->id)->whereHas('thread', function ($query) use ($search, $user) {
$query->where('threads.body', 'LIKE', '%' . $search . '%')
->orWhere('threads.title', 'LIKE', '%' . $search . '%');
})->orWhereHas('reply', function ($query) use ($search, $user) {
$query->where('replies.body', 'LIKE', '%' . $search . '%')
->where('replies.user_id', '=', $user->id);
})->get();
Anyone in the future who may need some additional assistance can visit this link: https://zaengle.com/blog/using-wherehas-in-laravel-polymorphic-relations
Apologies if the title is unclear, I'm unsure how to word it..
I'm creating a search function for filtering orders. Every order is assigned a user id or parent id (if the user is a child user) which is used to associate orders with users.
Eg: userid, parentid, name, product, delivery.
My problem is: searching by name etc. will return all results of that name regardless whether you're associated by id.
So I essentially need: where userid or parentid = current userid
followed by the search conditions: orwhere name, orwhere product, orwhere delivery = search term.
I currently have this working by checking the db for all search term matches, and then unsetting the data in my controller to only output the ones matching userid or parentid. Is there a better way to do this?
Order controller
$data = app('App\Http\Controllers\DbController')->getordersbysearch($search);
foreach($data as $row => $key){
if($key->Userid != $id || $key->parentid != $id){
unset($data[$row]);
}
else{
$key->Response = json_decode($key->Response);
}
dbcontroller
public function getordersbysearch($search){
$result = DB::table('orders')->where("Name", 'like', '%' . $search['search'] . '%')->orWhere("product", 'like', '%' . $search['search'] . '%')->orWhere("delivery", 'like', '%' . $search['search'] . '%')->get();
return $result;
}
Send the id to the function:
$data = app('App\Http\Controllers\DbController')->getordersbysearch($search, $id);
Then change your function to use this id:
public function getordersbysearch($search, $id) {
$result = DB::table('orders')
->where(function($q) use ($id) {
$q->where('parent_id',$id)
->orWhere('user_id',$id);
})->where(function($q) use ($search) {
$q->where("Name", 'like', '%' . $search['search'] . '%')
->orWhere("product", 'like', '%' . $search['search'] . '%')
->orWhere("delivery", 'like', '%' . $search['search'] . '%');
})->get();
return $result;
}
In my opinion, this kind of controller shouldn't exist. "DbController" should be a different layer like Service or Model.