简体   繁体   中英

laravel scout search with multiple model

I used this old code, and start refactor it with use of laravel/scout . This code is a simply search function thet search in posts and pages too, and show result mixed paginate.

Old code:

public function search($term) {
   $post = Post::where('title', 'LIKE', $term);
   $page = Page::where('content', 'LIKE', $term);
   $result = $page->union($post)->orderBy('created_at')->paginate();
   return $result;
}

New Code not working:

public function search($term) {
   $post = Post::search($term);
   $page = Page::search($term);
   $result = $page->union($post)->orderBy('created_at')->paginate(); 
   return $result;
}

get error: Method Laravel\Scout\Builder::union does not exist.

What is the best syntax for this problem?

Since Scout\Builder doesn't support union . And it would be non trivial to implement union functionality for all possible search engines supported by Scout.

However, Scout\Builder provides a query() function to customise the eloquent results query.

This provides kind of an escape hatch, where by scout can be leveraged on one model (out of the two)

public function search($term)
{
    $postQuery = Post::query()
        ->where('some_column', 'like', $term . "%");
    $results = Page::search($term)
        ->query(
            fn($query) => $query->union($postQuery)
                ->orderBy('created_at', 'desc')
        )
        ->paginate();
}

Laravel Scout - Customizing the Eloquent Results Query

For Algolia Engine

If using Algolia as search engine, there's Algolia Scout Extended which supports search with multiple models.

For other Engines

Another approach to search multiple models with Scout and get paginated results would be:

  • Get search results for individual models using Scout (using Model::search('query')->get(); )
  • Concat the resulting collections
  • Paginate the collection

Define a macro for Illuminate\Support\Collection in the boot method of a Service Provider (for eg in App\Providers\AppServiceProvider )

<?php

namespace App\Providers;

use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;
use Illuminate\Pagination\LengthAwarePaginator;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Collection::macro('paginate', function ($perPage, $total = null, $page = null, $pageName = 'page') {
            $page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);

            return new LengthAwarePaginator(
                $total ? $this : $this->forPage($page, $perPage)->values(),
                $total ?: $this->count(),
                $perPage,
                $page,
                [
                    'path'     => LengthAwarePaginator::resolveCurrentPath(),
                    'pageName' => $pageName,
                ]
            );
        });
    }
}

Then in the controller

public function search($term) {
   $post = Post::where('title', 'LIKE', $term)->get();
   $page = Page::where('content', 'LIKE', $term)->get();
   $result = $page->concat($post)->sortBy('created_at')->paginate(5);
   return $result;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM