How to exclude facets in filters or get conditional filters/conditionalFacets

App structure
Engine : national-parks-example
schema: [title, id, state, description].

Facet shows filters based on state field values.

I have following scenario
There are different users who can access documents from engine.

  1. User's will be able to access documents excluding some states (excluding restricted states for each type of users) .

  2. Show respected state facet/filters to users
    Example : Consider there are 2 users

User-1 : restricted states ['California']
User-2 : restricted states ['Texas', 'Florida']

* If User-1 logged in he can see all states documents  except 'California'
  * Facets will show all states in filters except 'California'
* For User-2 : show documents excluding state 'Texas' and 'Florida'
        * Facets will show all states in filters except 'Texas', 'Florida'

@Swapnil_Ghorpade You can achieve this with Signed Search Keys in App Search. There's a little more information on this post: Is there any way to implement document level security in app search?.

@JasonStoltz Thanks for the quick response.

What I want is ,
consider I have states array : ['Texas', 'Florida'] and I want to show all documents from engine excluding these two states.
so the result will return all documents where field state not equal to 'Texas' or 'Florida'

@Swapnil_Ghorpade To exclude two states from a search, you would use a "none" filter: https://swiftype.com/documentation/app-search/api/search/filters#combining-filters

"filters": {
    "none": [
      { "title": "Texas" },
      { "title": "Florida" }
    ]
  }

And again, if you're trying to restrict that at a user level, then you would generate a signed search key for that user with the above filter applied.

@JasonStoltz thanks looks like this will help me.

I tried this but is shows error PFA
I Have to show state facet in filters too.

https://codesandbox.io/s/national-parks-example-kdyms

I didn't realize you were using this with Search UI.

Query configuration looks a little bit different in Search UI: https://github.com/elastic/search-ui/blob/master/ADVANCED.md#query-config

The filters property is an Array of https://github.com/elastic/search-ui/blob/master/packages/react-search-ui/src/types/Filter.js.

So it would look like this:

searchQuery: {
    filters: [
      { field: "states", values: ["Texas", "California"], type: "none" }
    ]
}

That would apply the filter globally, for all users, on every query. This would not apply it at the user level, like you mentioned in your original post.

** NOTE: I realized just now that this doesn't work correctly when you have the disjunctive facet flag set for states. I will need to enter a bug for this. If you want to see it working you'll need to remove states from "disjunctiveFacets" for now **

@JasonStoltz thanks , yes now its showing result according to filters config.

If I remove state from disjunctiveFacets, its just removing that state from facets

if I add filters (none) in searchQuery and remove state from disjunctiveFacets then its showing correct UI but after that not able to filter result on facet selection.

Do you it ? PFA

Yeah looks like a bug.

FWIW, you won't need to do that in Search UI if you are going to used Signed Search keys, it will just be part of the key.

@JasonStoltz yeah its like a bug.

Right now don't want user level restriction. Its just a document field level restriction as done through filters config (using type none). Thanks its working !

Facets are not working when using these filters in searchQuery. could you please suggest me the way to work this ?

@Swapnil_Ghorpade

Luckily, we have a hook in the AppSearchAPIConnector which lets us modify requests and responses directly.

https://github.com/elastic/search-ui/blob/master/ADVANCED.md#api-config

Something like this should work for you for now, as a workaround:

beforeSearchCall: async (existingSearchOptions, next) => {
      const existingFilters = existingSearchOptions.filters || { none: [] };

      // Make sure none filter is applied to query
      const filters = {
        ...existingFilters,
        none: (existingFilters.none || [])
          .concat({
            states: "Texas"
          })
          .concat({
            states: "Florida"
          })
      };

      const results = await next({
        ...existingSearchOptions,
        filters
      });

      // Make sure none values are filtered out of facet results
      results.facets.states[0].data = results.facets.states[0].data.filter(
        d => !["Texas", "Florida"].includes(d.value)
      );
      return results;
    }
  });
1 Like

@Swapnil_Ghorpade You could also just use a signed search key as a workaround. That would ensure that all API requests are filtered.

@JasonStoltz Thank you. AppSearchAPIConnector works for me.