Reputation: 23073
I have a webpage that uses Algolia's React InstantSearch. It has a search bar and several refinements.
I want the user to be able to press a button and get a list of all matching results.
To get a list of all results, I need to use the Browse Index instead of the Search Index. The Browse Index allows retrieving all hits; the Search Index allows retrieval of only up to 1000 hits. However, the Browse Index should not be used in UIs. So I want to create an API endpoint my web server that uses the Browse Index in order return a list of matching hits given a search query.
I am able to successfully do this for a search query, but I can't figure out how to this for refinements.
Here is a sketch of what I have so far.
Back-end (in Ruby):
ALGOLIA_INDEX = Algolia::Index.new('Products')
class AlgoliaSearchController < ActionController::Base
def get_search_results
query = params['query']
hits = []
ALGOLIA_INDEX.browse({query: query}) do |hit|
hits << hit
end
render json: hits
end
end
Frontend:
import qs from 'qs';
import React, { useCallback, useState } from 'react';
import { InstantSearch } from 'react-instantsearch-dom';
function getSearchResults(query) {
const queryString = qs.stringify({
query,
})
return fetch(`/search_results?{queryString}`);
}
function App() {
const [searchState, setSearchState] = useState(null);
const onSearchStateChange = useCallback(searchState => {
setSearchState(searchState);
}, [searchState]);
const onClick = useCallback(() => {
console.log(getSearchResults(searchstate.query));
});
return (
<InstantSearch ... onSearchStateChange={onSearchStateChange}>
<button onClick={onClick}>Search</button>
</InstantSearch>
);
}
I can't find any resources that explain how to do search with refinements.
Things I've looked at so far:
I can try to map the searchState format to the Search API Parameters used by the Browse Index. I could write my own mapper from search state to a query, however, 1) this seems complex and I suspect I'm missing something simpler and 2) this seems like this should be open-sourced somewhere since I suspect I'm not the first to run into this issue.
There is an article, Backend InstantSearch
, that explains how to write a backend that can be plugged into the InstatSearch
component. However it doesn't explain how I could do a one-off search from the search state.
Upvotes: 3
Views: 504
Reputation: 1360
You are right that this is currently not exactly straightforward. The flow to get the raw search parameters you can use for "browse" is like this:
helper.getQuery()
to get the query parameters to applyA sandbox that illustrates this is: https://codesandbox.io/s/extending-widgets-luqd9
import React, { Component } from 'react';
import algoliaHelper from 'algoliasearch-helper';
import { connectStateResults } from 'react-instantsearch-dom';
class Downloader extends Component {
state = {
instructions: '',
};
onDownloadClick = () => {
// get the current results from "connectStateResults"
const res = this.props.searchResults;
// read the private "state" (SearchParameters) from the last results
const state = res && res._state;
// create a new "helper" with this state
const helper = algoliaHelper({}, state.index, state);
// get the query parameters to apply
const rawQuery = helper.getQuery();
this.setState({
instructions:
'Do a search backend with this:\n\nclient.browseAll(' +
JSON.stringify(rawQuery, null, 2) +
')',
});
};
render() {
return (
<React.Fragment>
<button onClick={this.onDownloadClick}>download</button>
<pre>{this.state.instructions}</pre>
</React.Fragment>
);
}
}
export default connectStateResults(Downloader)
Upvotes: 2