@CLab well, if it does not match the first condition, and not match the second condition, all matches by synonyms will be grouped in the end, that was what you asked for.
Ordering by the whole synonyms list is pretty straight forward, you just need to add an additional order by clause:
$results = Terms::query()
->where(function ($builder) use ($query) {
$builder
->orWhere('name', '=', $query)
->orWhere('name', 'like', $query)
->orWhereJsonContains('synonyms', $query);
})
->orderByRaw('CASE
WHEN name = ? THEN 1
WHEN name LIKE ? THEN 2
ELSE 3
END', [$query, $query])
->orderByRaw('CASE
WHEN name = ? THEN name
WHEN name LIKE ? THEN name
ELSE synonyms
END', [$query, $query])
->get();
This will first group your result set into buckets: first the exact matches, then the matches with the LIKE operator, and then the rest, in other words what matched something into the synonyms list.
The second order by, will sort the first two buckets by their name field, and the third bucket by the JSON array string representation, including non-matched synonyms.
Sorting the last bucket just using the matched synonyms is trickier, and actually depends on some decisions:
- Should I compare the whole synonyms list, including the ones that do not match the query, or just the matched ones?
- If one record matches a synonym in the second position, and the other matches a synonym in the fifth position, will this position differences will be taken into account?
Anyways, I don't use JSON arrays in MySQL that much, and if you want to dive in this last option, I can't help you anymore.
Good luck =)