Tieria
Tieria

Reputation: 433

Do not display duplicated posts on 2nd loop if 1st loop already displays the same posts in laravel

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

Answers (3)

Mohammad.Kaab
Mohammad.Kaab

Reputation: 1105

You can use the following query

$query2->where('definition','like','%'.$keyword.'%')->where('word','not like','%'.$keyword.'%')

Upvotes: 0

robotu
robotu

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

Akhtar Munir
Akhtar Munir

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

Related Questions