ra-supabase icon indicating copy to clipboard operation
ra-supabase copied to clipboard

How is full text search supposed to work?

Open 25747 opened this issue 3 years ago • 1 comments

Awesome tool that just works out of the box like everything else react-admin! I'm trying to play with some more functionality but I don't understand how fullTextSearchFields is intended to operate when there are multiple fields. On the client side the search fields are added on as 'ilike()' parameters, but the standard behavior is to find any items where ALL the parameters are 'matched'.

For example, a "player" resource where I'd like to have two fields available for full text search:

{
  fields: [ "name", "where_now", ... ],
  fullTextSearchFields: ["name", "where_now"],
}

in my list component i have the following filter:

[
  <SearchInput source="q" alwaysOn />,
];

when searching for something, like the name "mason", this is the resulting query: image

it is looking for anything where name is like 'mason' and also where_now is like 'mason'. Instead, shouldn't it be looking for an OR condition between them? I can imagine trying to build an OR( ) query like

query.or('name.ilike.("mason"),where_now.ilike.("mason")')
//idk if this is valid

Do I need to do some work on the Supabase side to deal with this condition? FWIW, the fullTextSearchFields option works as expected when there is only one field since the single ilike condition is met.

RA versions:

    "@supabase/supabase-js": "^1.31.0",
    "ra-supabase": "^1.2.1",
    "react-admin": "3.19.10",

25747 avatar Mar 14 '22 16:03 25747

after some playing around I found a valid form of the query i was imagining, and it fit what i was expecting:

.or(`name.ilike.%mason%,where_now.ilike.%mason%`)

i modified the dataprovider's getList function near the end where it checks for a 'q' field to complete the query. Instead of adding on successive .ilike( ) selectors, I build a string and pass it into one or( ) selector at the end:

if (q) {
    let queryString = ""; //create a query string to put into an or( ) selector
    const fullTextSearchFields = Array.isArray(resourceOptions)
      ? resourceOptions
      : resourceOptions.fullTextSearchFields;

    fullTextSearchFields.forEach((field, index, array) => {
      /* query = query.ilike(field, `%${q}%`); */ // existing method - add on successive ilike selectors

      queryString += `${field}.ilike.%${q}%`; // new method - concatenate the ilike queries into one string

      if (index < array.length - 1) {
        queryString += ","; //add commas between the selectors, but not at the end
      }
    });
    query.or(queryString); //add an or( ) selector using the built query string

In the case of above the above example, now my list returns with the two "Players" whose names contain 'mason'. I can also search for 'retired' and find the 8 "Players" with 'retired' in where_now.

I will add in other fields and see if this works like I expect it to. Does this implementation make sense?

25747 avatar Mar 14 '22 18:03 25747

This has now changed in 2.0.0. See the release notes

djhi avatar Mar 06 '23 16:03 djhi