-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Example searching via relations attributes #11
Comments
protected function applySearchableJoins ($ query)
{
foreach ($ this-> searchableJoins () as $ table => $ join) {
$ joinMethod = $ join [2] ?? 'leftJoin';
$ query -> {$ joinMethod} ($ table, $ join [0], '=', $ join [1]);
}
$query-> groupBy ('listings.id');
} also pls send me sqldump file of your database so I can test it in my local. |
@ajcastro I tested without success.I did not know why right join give same results as left join. Here is my SQL dump for tests. |
@VisualLight.. right join will really include each rows in keywords that's why it duplicates those rows... here is what you can do... in your // Assuming that your $searchable property looks like this
class Listing extends Model
{
protected $searchable = [
'columns' => [
'listings.title',
'listings.description',
'categories.title',
'keywords.title',
'user_name' => 'CONCAT (users.firstname, "" , users.lastname)',
],
];
}
class ExactSearch extends SublimeSearch
{
public function sortColumns()
{
// Exclude the keywords.title
return collect(parent::sortColumns())->reject(function($column) {
return $column === 'keywords.title'; // exclude 'keywords.title' in sort by relevance
})->all();
}
}
// Then call distinct() after search() to remove duplicate results
$query->search($searchStr)->distinct(); |
@ajcastro the final result is the same. $query->search($str)->distinct()->paginate(1) give me a not correct value when $query->lastPage(); ==> 11 (it will be 2). lastPage() is used in Ajax (show more results button) and is provided natively by eloquent. paginate() give me more pages than expected. |
@visualight are you sure you exclude the |
Yes. Here is a resume of my configuration : Listing Model
ExactSearch Model
SQL DUMP
Results here => http://dev3.hybris-studio.be/sql |
Note pagination :
Results here : http://dev3.hybris-studio.be/test-paginate Edit : Response for total is 11. It will be 2 if I disable keywords searching. |
^ @visualight Please fix this so it display only string sql, because it is currently dumping the query builder instance..
^ Please return the paginator instead of dumping it so we only see the actual data |
I am thinking of a feature to search on the relation instead of doing join for that use-case. <?php
class Listing extends Model
{
protected $searchable = [
'columns' => [
'listings.title',
'listings.description',
'categories.title',
'author_full_name' => 'CONCAT(users.firstname, " ", users.lastname)',
],
'joins' => [
'users' => ['users.id', 'listings.user_id'],
'categories' => ['categories.id', 'listings.category_id'],
],
'relations' => [
'keywords' => ['title'],
],
];
/**
* Override defaultSeach to exact search match
* @return ExactSearch
*/
public function defaultSearchQuery()
{
return new ExactSearch(
$this,
$this->searchableColumns(),
$this->sortByRelevance,
'where',
$this->searchable['relations'] ?? [] // let's pass our relations here
);
}
}
class ExactSearch extends SublimeSearch
{
protected $relations;
/**
* Override construct so we can pass the relations option
*/
public function __construct(
$query,
$columns = [],
$sort = true,
$searchOperator = 'where',
$relations = []
) {
parent::__construct($query, $columns, $sort, $searchOperator);
$this->relations = $relations;
}
protected function parseSearchStr($searchStr)
{
return "%{$searchStr}%"; // produces "where `column` like '%{$searchStr}%'"
}
/**
* Override search() method so we can perform the search in the relations
*/
public function search($searchStr)
{
$query = parent::search($searchStr);
/*
$this->relations looks like this:
[
'keywords' => ['title'],
],
*/
$searchStr = $this->parseSearchStr($searchStr);
foreach ($this->relations as $relation => $columns) {
$query->orWhereHas($relation, function ($query) use ($searchStr, $columns) {
foreach ($columns as $column) {
$query->where($column, 'like', $searchStr);
}
});
}
return $query;
}
} |
@ajcastro Dumps have been fixed. |
@ajcastro Your patch works like a charm. Have you planned an update for a simpler integration or should I just leave the patch as such? |
@visualight great! |
I thought about this for a while. In the meantime, the acceptable solution is like this, overriding the methods so that anyone can customize it on their own application level. |
The structure of my database is as follows:
Table listings:
Table Keywords:
I query the keywords table against the listing_id to find out if there are keywords for the listing table.
Suddenly my searchable results gives me more results than expected. 11 results for 4 real records in the listings table). Changing the join method does not change anything. If I apply distinct () in the SQL request, the elements are well filtered but the response for:
I guess if I apply a groupBy it will solve the problem but goupBy seems not to want to work.
I have the following error if I apply as follows:
LISTING MODEL
ERROR
SQLSTATE [42000]: Syntax error or access violation: 1055 Expression # 29 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'hybrisdev3.keywords.title' which is not functionally dependent on columns in GROUP BY
SQL
select
listings
. *, (LOCATE ('b', CONCAT (IFNULL ((listings.title), ''), IFNULL ((listings.description), ''), IFNULL ((categories.title), '' ), IFNULL ((keywords.title), ''), IFNULL ((CONCAT (users.firstname, "", users.lastname)), '')), 1) + LOCATE ('o', CONCAT (IFNULL ( (listings.title), ''), IFNULL ((listings.description), ''), IFNULL ((categories.title), ''), IFNULL ((keywords.title), ''), IFNULL ((CONCAT (users.firstname, "", users.lastname)), '')), 2) + LOCATE ('u', CONCAT (IFNULL ((listings.title), ''), IFNULL ((listings.description), ''), IFNULL ((categories.title), ''), IFNULL ((keywords.title), ''), IFNULL ((CONCAT (users.firstname, "", users.lastname)), '')) , 3) + LOCATE ('l', CONCAT (IFNULL ((listings.title), ''), IFNULL ((listings.description), ''), IFNULL ((categories.title), ''), IFNULL ( (keywords.title), ''), IFNULL ((CONCAT (users.firstname, "", users.lastname)), '')), 4) + LOCATE ('a', CONCAT (IFNULL ((listings.title ), ''), IFNULL ((listings.description), ''), IFNULL ((categories.title), ''), IFNULL ((keywords.title), ''), IFNULL ( (CONCAT (users.firstname, "", users.lastname)), '')), 5) + LOCATE ('n', CONCAT (IFNULL ((listings.title), ''), IFNULL ((listings.description ), ''), IFNULL ((categories.title), ''), IFNULL ((keywords.title), ''), IFNULL ((CONCAT (users.firstname, "", users.lastname)), '' ))), 6) + LOCATE ('g', CONCAT (IFNULL ((listings.title), ''), IFNULL ((listings.description), ''), IFNULL ((categories.title), ''), IFNULL ((keywords.title), ''), IFNULL ((CONCAT (users.firstname, "", users.lastname)), '')), 7) + LOCATE ('e', CONCAT (IFNULL ((listings .title), ''), IFNULL ((listings.description), ''), IFNULL ((categories.title), ''), IFNULL ((keywords.title), ''), IFNULL ((CONCAT (users .firstname, "", users.lastname)), '')), 8) + LOCATE ('r', CONCAT (IFNULL ((listings.title), ''), IFNULL ((listings.description), '' ), IFNULL ((categories.title), ''), IFNULL ((keywords.title), ''), IFNULL ((CONCAT (users.firstname, "", users.lastname)), '')), 9 ) + LOCATE ('i', CONCAT (IFNULL ((listings.title), ''), IFNULL ((listings.description), ''), IFNULL ((categories.title), ''), I FNULL ((keywords.title), ''), IFNULL ((CONCAT (users.firstname, "", users.lastname)), '')), 10) + LOCATE ('e', CONCAT (IFNULL ((listings .title), ''), IFNULL ((listings.description), ''), IFNULL ((categories.title), ''), IFNULL ((keywords.title), ''), IFNULL ((CONCAT (users .firstname, "", users.lastname)), '')), 11)) AS sort_index fromlistings
left joinusers
onusers
.id
=listings
.user_id
left joincategories
oncategories
.id
=listings
.category_id
left joinkeywords
onkeywords
.listing_id
=listings
.id
wherelistings
.status
=? and (listings.title like "% boulangerie%" OR listings.description like "% boulangerie%" OR categories.title like "% boulangerie%" OR keywords.title like "% boulangerie%" OR CONCAT (users.firstname, "" , users.lastname) like "% boulangerie%") andlistings
.deleted_at
is null group bylistings
.id
,listings
.id
,listings
.id
order bysort_index
ascLISTING MODEL
How I can get only 4 record s as expected without a groupBy method OR how i can apply the groupBy on the search query ? Thank you
The text was updated successfully, but these errors were encountered: