elastic/search-ui

Calling setFilter with an array of values sets the filter value to an array of arrays

j23schoen opened this issue · 6 comments

Describe the bug
I'm using a my own component with the withSearch HOC to set a filter. If I call setFilter('industry', ['ai', 'enterprise']) the value of the filter is set to an array of arrays, like this: `[ [ 'ai', 'enterprise' ] ].

To Reproduce
Steps to reproduce the behavior:

I created a react app that looks like this:

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <SearchProvider config={config}>
          <SearchBox>
          </SearchBox>
          <Results />
          <ArrayFilter />
        </SearchProvider>
      </header>
    </div>
  )
}

const ArrayFilter = withSearch(({ setFilter, filters }) => ({
  setFilter, filters
}))(ArrayButton)

function ArrayButton({ setFilter, filters }) {
  console.log(filters)
  return <button type='button' onClick={() => setFilter('industry', ['ai', 'enterprise'])}>array filter</button>
}

Clicking the button results in an error from the search:

{
	"error": {
		"root_cause": [
			{
				"type": "parsing_exception",
				"reason": "[term] query does not support array of values",
				"line": 1,
				"col": 451
			}
		],
		"type": "x_content_parse_exception",
		"reason": "[1:451] [bool] failed to parse field [filter]",
		"caused_by": {
			"type": "x_content_parse_exception",
			"reason": "[1:451] [bool] failed to parse field [filter]",
			"caused_by": {
				"type": "parsing_exception",
				"reason": "[term] query does not support array of values",
				"line": 1,
				"col": 451
			}
		}
	},
	"status": 400
}

And the filters object on the request state look like this:

{
  "filters": [
    {
      "field": "industry",
      "values": [
        [
          "ai",
          "enterprise"
        ]
      ],
      "type": "all"
    }
  ]
}

Expected behavior
I would expect the values prop on the industry filter to be [ 'ai', 'enterprise' ] and for the query builder to handle creating the query with an array of term filters applied.

I can work around this by calling addFilter twice

Screenshots
If applicable, add screenshots to help explain your problem.

Which backends and packages are you using:
Backend: [Elasticsearch, ]
Packages: [react-search-ui, search-ui-app-search-connector, etc.]

Hey
Yeah seems like a bug on the setFilter action. Prepare fix soon. Till then you can use addFilter with array values:
addFilter("states", ["California", "Alaska"], "any")
Thank you for reporting a bug

Hey Yeah seems like a bug on the setFilter action. Prepare fix soon. Till then you can use addFilter with array values: addFilter("states", ["California", "Alaska"], "any") Thank you for reporting a bug

Awesome thanks for fixing this so quickly!

Hey @yansavitski I have a field called "deadline" and in some of the documents, that field doesn't exist. Can I use addFilter() to filter documents that do not have "deadline" field? If not any other suggestion how it can be achieved? Thanks!

Hey, you can filter out documents that do not contain certain field using addFilter by setting FieldType as "none" .
For example: addFilter("states", "Alaska", "none");
This would filter result with states field "Alaska"

Hey @saarikabhasi thanks for the response. But my requirement is not like that. I want to filter out docs which do not have "state" field. Something like addFilter("states", null, "all");

Hey @chris7716 you could achieve this by using Elasticsearch API connector by customizing Elasticsearch request body before sending to Elasticsearch.

To filter out documents having a specific field, you could construct a compound query using must_not and exists term level queries.

For example:


const connector = new ElasticSearchAPIConnector(
  {
    host:<cloud_id>,
    index: <index_name>,
    apiKey:<api_key>,
  },
  (requestBody) => {
    requestBody.post_filter = {
      bool: {
        must_not: {
          exists: {
            field: "states",
          },
        },
        ...requestBody.post_filter?.bool,
      },
    };
    return requestBody;
  }
);

Please checkout this tutorial on our documentation to learn more about setting up Elasticsearch connector.