Appropriate Use case?

Hi! I’m building a react app that utilizes react-instantsearch to search an index of user uploaded contacts. I’d like to allow the user to filter / search down to a subset of the entire contacts index and then send a message to all contacts that meet the current search parameters

My (perhaps naive) plan to is:

  1. Allow user to search. Keep track of current search with onSearchStateChange
  2. When user has filtered the records to their specifications, they can click on a button which triggers a modal where they provide the message content (among other things).
  3. When the user hits “send” it dispatches an api call to the backend with all the message parameters along with the search parameters derived from onSearchStateChange
  4. The backend then uses that searchState information to query my indexes again, grab all necessary data from the records and dispatch the message.

Question: Is this the right approach? Are there any pitfalls / concerns I should be aware of as I implement this? Any better ways to deal with a subset of records? Unfortunately I don’t think I can take a “shopping cart” approach and allow users to select individual records for message sends because in some cases they may want to send messages to thousands of contacts and needing to select each individually would be too much. Thoughts?

Hi @jake,

Thanks for contributing to the forum :slight_smile:

For your use case, it seems a bit hairy. The theory that you lay out is sound. However the state used in react-instantsearch is not usable directly by any of the API clients. Only the actual queries to Algolia can be replayed in a backend client.

However in react-instantsearch, you have the ability to provide your own JS API client. If you hijack the search function of the client that you provide, you should be able to save the queries that are transferred to this method. When your user wants to trigger the mailing, then you could use the saved queries.

In practice that would mean to do something like:

const client = algoliaClient();
const oldSearch = client.search;
client.search = function(qs, cb) {
   window.lastQueries = qs;
   return oldSearch.call(client, qs, cb);
}

And then passing this new client to the InstantSearch component. When the time comes you want to replay the search in your backend, just send it the content of the window.lastQueries and let it use the search method for your backend client.

However, @marielaure.thuret might have a better idea on how to proceed there :slight_smile:

1 Like

Hi @jake!

I think you can directly retrieve the ids of the hits filtered by your users by using the connectHits connector. That way when the user wants to send a message, then you can also send to your back-end directly the corresponding contact ids. You may need to play with the paginationLimitedTo and hitsPerPage settings to be sure that your user can retrieve all their contacts (if more than 1000).

Steps would be:

  • use connectHits to display hits.
  • the user select its contacts and their ids are saved in a variable (or every hits id that are returned are saved).
  • the user click on a button and write his message.
  • the user click on send, then the message and all the hits ids are sent to the backend.
  • retrieve the data you need using the hits ids with your backend client.

There’s one question here though about the interface. How many contacts you will display to the user? Let’s say you’re displaying the first ten that matches the filters, will the message be sent to all the other one? This can change a bit the steps I just mentioned.

Otherwise if this strategy can’t work for you, you’ll need to pass the searchState and translate it in a way that your backend client can understand. Which client are you using?

Thanks @marielaure.thuret - if I go the connectHits route, is it possible to utilize attributesToRetrieve and limit attributes to just the objectID and thus keep that payload as light as possible. I imagine doing so would really help to push up the paginationLimitedTo limits and stay performant.

Ahh… It seems that is exactly what Configure is for.

<Configure attributesToRetrieve={[...]} seems to be working to limit what is retrieved.

1 Like

Sorry I didn’t see your previous answer. That’s nice that you find what you were looking for!

Happy coding :slight_smile:

1 Like