laravel-scout-tntsearch-driver
laravel-scout-tntsearch-driver copied to clipboard
Relation search
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!
Same question! Would really appreciate an answer!
Hi, $results = $model->companies->search('Company name')->get() ->load('companies');
In the "load", you can list several relationships (example: ->load('companies', 'addresses', etc...)).
$city = \App\City::first();
When i do $companies = $city->companies->search('company name');
in dd($companies);
i'm getting false
(boolean
)
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
But i have hasMany()
relation :(, this approach not working on hasmany relations.
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;
});
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" } }
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 That looks awesome. Thanks for sharing the solution with us.
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
@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.
@tranghaviet what if child row updates? how is that synced to the index??
@akkhan20 If you find the answer, let us know..
@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
@tranghaviet what if child row updates? how is that synced to the index??
use touches