laravel-scout-tntsearch-driver icon indicating copy to clipboard operation
laravel-scout-tntsearch-driver copied to clipboard

Relation search

Open pwnz22 opened this issue 7 years ago • 15 comments

Hi all!

I need help to search in models hasMany relation, something like: $model->companies->search('Company name')->get();

My model relation looks like this;

public function companies() {
    return $this->hasMany(Company::class);
}

Thanks!

pwnz22 avatar Mar 13 '17 09:03 pwnz22

Same question! Would really appreciate an answer!

levonmanucharian avatar Mar 22 '17 05:03 levonmanucharian

Hi, $results = $model->companies->search('Company name')->get() ->load('companies');

In the "load", you can list several relationships (example: ->load('companies', 'addresses', etc...)).

reals79 avatar Mar 30 '17 09:03 reals79

$city = \App\City::first();

When i do $companies = $city->companies->search('company name'); in dd($companies); i'm getting false (boolean)

pwnz22 avatar May 15 '17 06:05 pwnz22

I am using this in a Model and it is working in one to many relationship (Helpers table and Categories table)
Helper.php

/**
* Get the indexable data array for the model.
*
* @return array
*/
public function toSearchableArray()
{
    return [
        'id' => $this->id,
        'title' => $this->title,
        'content' => $this->content,
        'code' => $this->code,
        'category' => $this->category['name'],
    ];
}

public function Category()
{
    return $this->belongsTo('App\Category');
}

This should be helpful https://laracasts.com/discuss/channels/laravel/scout-how-to-search-in-relations-and-counts

the94air avatar May 16 '17 19:05 the94air

But i have hasMany() relation :(, this approach not working on hasmany relations.

pwnz22 avatar May 17 '17 08:05 pwnz22

The work-around for HasMany relationships is clunky, and may prove to be a performance issue if you have thousands of search results.

Instead of $blog->posts()->search('...')->get();, I do the search, then filter by blog ID:

    $posts = (new Post)->search(request('searchText'))->get();
    $posts = $posts->filter(function ($post) use ($blog) {
        return $post->blog_id === $blog->id;
    });

mikebronner avatar Jul 11 '17 21:07 mikebronner

Hi I'm sure this way not the best way for resolve this problem and i think Taylor and his team must be resolve it issue but i resolve it with another way: i have a User model and any user have many Device so in user model i have this method

public function devices() { return $this->hasMany(Device::class); }

first i defined some variable as below

protected $searchableColumns = [ 'name', 'family', ]; protected $searchableInnerColumns = [ 'devices' => 'imei', ];

then i wrote "toSearchableArray" as following: public function toSearchableArray() { $result = []; if (!sizeof($this->searchableColumns)) { $result = collect($this); } else { $result = collect([ 'id' => $this['id'], ]); foreach ($this->searchableColumns as $searchableColumn) { $result->put($searchableColumn, $this[$searchableColumn]); } } if (sizeof($this->searchableInnerColumns)) { foreach ($this->searchableInnerColumns as $searchableInnerColumnKey => $searchableInnerColumnValue) { $values = $this->{$searchableInnerColumnKey}() ->select($searchableInnerColumnValue) ->get() ->toArray(); $counter = 0; foreach ($values as $value){ $result->put($searchableInnerColumnKey . "-" . $searchableInnerColumnValue."-".$counter, collect($value)->get($searchableInnerColumnValue)); $counter++; } } } return $result->toArray(); }

and result in Postman like this:

{ "id": 3, "name": "Jed Purdy", "family": "Upton", "devices-imei-0": { "imei": "79663" }, "devices-imei-1": { "imei": "99958" } }

Alive2212 avatar Oct 01 '17 14:10 Alive2212

My solution (if you want to search company name): In Model:

public function toSearchableArray()
{
        $a = $this->toArray();
        $companies = $this->companies()->get(['name'])->map( function ($company) {
                  return $company['name'];
         });
         $a['companies'] = implode(' ', $companies->toArray());
         return $a;
}

run php artisan scout:import App\\ModelName (use tntsearch:import won't work);

tranghaviet avatar Oct 21 '17 08:10 tranghaviet

@tranghaviet That looks awesome. Thanks for sharing the solution with us.

the94air avatar Oct 21 '17 09:10 the94air

My Solution What I Just Did Is Make The Model That Has Relationships I Also Made It Searchable And Imported (Indexed )

So I Just Qeury It As Usually

$categories = Category::search($request->q)->get();

This Is Work Fine

zymawy avatar Dec 28 '17 14:12 zymawy

@tranghaviet works great - thanks! You can make this shorter using the collection->implode method:

public function toSearchableArray()
{

    return [
        'id'       => $this->id,
        'products' => $this->products()
            ->get(['name'])
            ->implode('name', ' ')
    ];
}

... or even 'products' => $this->products->implode('name', ' ') for "light" models.

rico avatar Nov 25 '18 11:11 rico

@tranghaviet what if child row updates? how is that synced to the index??

jampack avatar Mar 13 '19 09:03 jampack

@akkhan20 If you find the answer, let us know..

Ssy3 avatar Apr 02 '19 17:04 Ssy3

@Ssy3 updating child model does not update the parent when you use it like this. Instead, you should manually update the index by calling the searchable method on the relationship

davehowson avatar Dec 19 '20 10:12 davehowson

@tranghaviet what if child row updates? how is that synced to the index??

use touches

x3mart avatar Apr 01 '21 21:04 x3mart