Reputation: 433
I'm building a dictionary website with laravel6.
And when a visitor search a keyword, 2 queries will run to find posts.
Controller.php
public function index(Request $request)
{
$keyword = $request->input('keyword');
$query = Post::query();
$query2 = Post::query();
if(!empty($keyword)){
$query->where('word','like','%'.$keyword.'%');
$data = $query->orderby('word', 'DESC')->paginate(4);
$query2->where('definition','like','%'.$keyword.'%');
$data2 = $query2->orderby('definition', 'DESC')->paginate(4);
return view('index')->with(['keyword' => $keyword])->with(['data' => $data])->with(['data2' => $data2]);
}
}
Then, show 1st query & 2nd query result.
index.blade.php
@foreach($data as $val)
<div class="post">
<h2>{{$val->word}}</h2>
<p>{{$val->definition}}</p>
</div>
@endforeach
@foreach($data2 as $val2)
<div class="post">
<h2>{{$val2->word}}</h2>
<p>{{$val2->definition}}</p>
</div>
@endforeach
The problem is, 2nd loop ($data2) shows duplicate posts of $data. So how can I not display duplicate posts on $data2 loop?
I tried like:
@foreach($data2 as $val2)
@if($val2->id !== $val->id)
<div class="post">
<h2>{{$val2->word}}</h2>
<p>{{$val2->definition}}</p>
</div>
@endif
@endforeach
But didn't work. Appreciate any suggestion.
Upvotes: 0
Views: 165
Reputation: 1105
You can use the following query
$query2->where('definition','like','%'.$keyword.'%')->where('word','not like','%'.$keyword.'%')
Upvotes: 0
Reputation: 213
If you use the pagination for queries the only solution is to implement code in the controller. In the second foreach of the view it is not possible to know all the values of the first foreach.
If I understand your question correctly, you can change your approach and use a single query. In the controller you can write a query more or less like this:
$data = Post::select('word', 'definition')
->where(function ($query) use ($keyword) {
$query->where('word', 'like', '%' . str_replace(' ', '%', $keyword) . '%')
->orWhere('definition', 'like', '%' . str_replace(' ', '%', $keyword);
})
->paginate(4);
You have no duplicate posts and you can also search with multiple words separated by a space (for multiple search the order of words must be that of the text).
EDIT: This the solution with two query. The first query rest the same, the second query is filtered by the id list of the first query:
$listDataId = Post::where('word','like','%'.$keyword.'%')>orderby('word', 'DESC')->get()->pluck('id');
$query2->where('definition','like','%'.$keyword.'%');
$data2 = $query2->whereNotIn('id', listDataId)->orderby('definition', 'DESC')->paginate(4); // whereNotIn exclude the first query value
Upvotes: 1
Reputation: 1769
You can also do that with laravel's collection. As you might have noticed each query in laravel is a collection, so you can play with collections like you can search here https://laravel.com/docs/7.x/collections#method-merge
public function index(Request $request)
{
$keyword = $request->input('keyword');
$query = Post::query();
$query2 = Post::query();
if(!empty($keyword)){
$query->where('word','like','%'.$keyword.'%');
$data = $query->orderby('word', 'DESC')->paginate(4);
$query2->where('definition','like','%'.$keyword.'%');
$data2 = $query2->orderby('definition', 'DESC')->paginate(4);
//collection starts here.
//It will replace duplicate keys and will give you one collection
$merged = $data->merge($data2);
//Now you will have only one foreach loop in the view.
return view('index')->with(['keyword' => $keyword])->with(['data' => $merged]);
}
}
Upvotes: 0