Search based on an object

We are using Algolia for user searches. Amongst other things, each user has a list of interests. We’ve recently added a rating feature, where each user can obtain a rating on a scale between 1 and 5 for a given interest.

For instance, user 1 can have interest x with rating 3 and interest y with rating 5 whereas user 2 can have interest x with rating 4 and interest y with rating 1.

We’d like to be able to search based on this. So basically, we want to be able to tell Algolia to e.g. give us all users with interest x rated 3 or higher. Thus, we need to search based on the object {interestName: string; rating: number}

My first attempt has been using connectRefinementList (we need custom UI). I pass along a stringified version of the object to the refine function and, as expected, I get the following entry in the facetFilters

["interestRatings:{\"interestName\":\"Something\",\"rating\":4}"]

which is exactly what I expect, however, Algolia merely responds to that with “Unknown refinement interestRatings” and no data. I’ve also tried changing the type of the parameter passed to the refine function provided by connectRefinementList from string[] to any[] and pass along the object itself which (not surprisingly) yields the following the facetFilters

["interestRatings:[object Object]"]

This yields the same result as when passing along the stringified version of the object, no hits returned and the message “Unknown refinement interestRatings”. This leads me to my two questions:

  1. Is this kind of search even possible with Algolia? And if so, how do I make Algolia accept my object as a valid filter? It seems to me Algolia does not know how to handle a complex object as opposed to a string value of an attribute to include or a range of a specific attribute to filter by.
  2. If it is possible, is it doable without writing a custom connector? It seems to me to simply be a special case of the array filtering task. Instead of filtering based on an array of string, I’d merely like to filter based on an array of objects - thus, it seems unnecessary to write my own custom connector when it’d be obvious to reuse your refinementList connector

Hi @nn1,

Could you do two things to help us better understand your issue:

  • share with us the current structure of your record?
  • share with us a codesandbox with minimum code needed to reproduce your issue?

We have sandboxes available here with much of the boilerplate finished: https://github.com/algolia/create-instantsearch-app#previews

Thank you!

The part of our record structure relevant to my question is the following

type User {
  interests?: string[]
  interestRatings?: Array<{
    interestName: string;
    rating: number
  }>
}

Unfortunately, creating a minimum reproducible example is easier said than done as we’d either have to give you access to our user search in our stage environment (which we’d rather not do as that would create a public backdoor to our user information through stage) or set up a separate search for that purpose only (which seems like a lot of work for something which could be communicated in writing instead).

Also, since my original inquiry is a question regarding the possibilities and limitations of your search rather than a bug report, I don’t see the need for a minimal reproducible example. Instead, I’ll try to provide a better explanation:

Usually, when filtering in Algolia, it’s done in one dimension. Thus, if I want to filter my users to only display users with “SomeInterest”, I use a ListRefinement, provide it with the attribute name “Interests” (as per the structure above) and refine it with refine(["SomeInterest"] and I have all users with that particular interest. I’ve filtered my attribute based on one dimension which is the name of the interest the resulting users should have.

Now to my use case. I want to filter in two dimensions instead. So, to mimic the example just described for this use case, I provide a ListRefinement with the attribute name “InterestRatings” (as per the structure above), however, this time around I want to display users who have rating 3 for the interest “SomeInterest”. Thus I am interested in filtering based on an interest name and its accompanying value simultanously.

In my mind, the logical way to do this would be to call refine([{interestName: "SomeInterest", rating: 3}]) with the attribute name "InterestRatings. I’d then expect Algolia to return users whose interestRatings array contains the entry {interestName: "SomeInterest", rating: 3}. This is just like when I call refine(["SomeInterest"]) with attribute name “Interests”, Algolia returns users whose interest array contains the entry "SomeInterst".

  1. Is it possible to use listRefinement (or any other refinement for that matter) in this way?
  2. If not, is it possible to achieve this behavior (filtering based on an attribute whose values are objects as opposed to strings or numbers) in some other way?

Hi @nn1,

Thanks for the additional detail.

If your current record structure is close to this:

{
  "name": "User 1",
  "interestRatings": [
    {
      "interestName": "drawing",
      "interestRating": 5
    },
    {
      "interestName": "running",
      "interestRating": 1
    }
  ]
}

You will need to separate the "interestRatings" into separate records:

{
  "name": "User 1",
  "interestRatings": [
    {
      "interestName": "drawing",
      "interestRating": 5
    }
  ]
} 
{
  "name": "User 1",
  "interestRatings": [
    {
      "interestName": "running",
      "interestRating": 1
    }
  ]
}

With the separate records, you can then use two refinement lists to refine on two facets for a conjunctive filtering: facet1: value AND facet2: value)