instantsearch
instantsearch copied to clipboard
Ability to use multiple fields in range widget
We are implementing an instantsearch on our wocommerce site, and in our scenario we store prices in many fields (ie. depending on current user group - they will receive a certain discount, ie.:
{
id: 123,
title: "apple ipad 32gb black",
price: 200,
price_groupA: 180,
price_groupB: 160,
price_groupC: 150
}
We basically want to be able to generate the request with the OR condition on all price fields that are relevant to currently logged in user.
current range widget is based solely on 1 price "field" and I don't seem to be able to find anything for query override, ie. current query would translate to something like:
SELECT * FROM products WHERE price BETWEEN 50 AND 100
But i'd like to be able to re-construct that query before it is sent to algolia to convert to something like:
SELECT * FROM products WHERE price BETWEEN 50 AND 100 OR price_groupA BETWEEN 50 AND 100 OR price_groupC BETWEEN 50 AND 100
Example that I showed nearly doesn't make any sense, but I was trying to make it a little more clear. Real reason is that our user can be member of multiple user groups at the same time, and we want to provide best possible price based on their user group - price associations.
Is this even a right approach? if it is - how can we achieve this type of behaviour, and if it's not - is there something that anyone could recommend to solve this problem?
Hi @virtuman if I understand well, you have different prices given some user data. But do you want to show one price range or multiple of them to a single user on a single page?
Well, we don't really care if all of the prices are viewable by the user that is not supposed to see them, it's not that big of an issue. As far as displaying the proper price on the client we do that with the template helper and it does that perfectly well. The problem is with structuring the price range request through rangeSlider widget, that would take an OR condition on specified price fields as in the example in my original post, ie:
SELECT * FROM products WHERE price BETWEEN 50 AND 100 OR price_groupA BETWEEN 50 AND 100 OR price_groupC BETWEEN 50 AND 100
or I guess in the rangeSlider widget language something like this:
attributeName: ['price', 'sale_price', 'regular_price', 'msrp', 'price_codeA', 'price_codeB'] although we still need to display price ranges based on some pricing, but with multi-field attribute maybe it could take HIGHEST and LOWEST values from all of the specified attributes ?
search.addWidget(
instantsearch.widgets.rangeSlider({
container: '#price',
>>attributeName: 'price', <<< This attribute to take in multiple values and based output on
cssClasses: {
header: 'facet-title'
},
templates: {
header: 'Price'
},
step: 10,
tooltips: {
format: function(rawValue) {
return '$' + Math.round(rawValue).toLocaleString();
}
}
})
);
Ok, thanks, let's say you have only one slider that goes from 0 to 500, the users sets it to [50 - 200]. Do you want to send to Algolia this:
SELECT * FROM products WHERE price BETWEEN 50 AND 200 OR price_groupA BETWEEN 50 AND 200 OR price_groupC BETWEEN 50 AND 200
Or this:
SELECT * FROM products WHERE price BETWEEN 50 AND 300 OR price_groupA BETWEEN 50 AND 150 OR price_groupC BETWEEN 50 AND 400
?
= Do you want to apply some manual adjustement to the slider value(s) to be sent to Algolia?
attributeName: ['price', 'sale_price', 'regular_price', 'msrp', 'price_codeA', 'price_codeB'] although we still need to display price ranges based on some pricing, but with multi-field attribute maybe it could take HIGHEST and LOWEST values from all of the specified attributes ?
I think I get this, you mean that if you use multiple prices attributes on a single widget, as for the start and end range (when slider starts) we could just take the highest and lowest values?
Also, do you know early on what are the price fields relevant to the current user?
Yes, no, and yes :)
lookup for products in specified range should construct something like this:
SELECT * FROM products WHERE price BETWEEN 50 AND 200 OR price_groupA BETWEEN 50 AND 200 OR price_groupC BETWEEN 50 AND 200
Yes, we always know on the client side what price codes (or attribute names) that user qualifies for.
And yes, your last question is exactly what I had in mind, lowest and maximum values on the range slider should take into the account lowest and highest points from across all attributes that are specified in the attributeName
property.
Do you think there's a merit for this implementation? I'm sure this would be beneficial to a large mass of users that have MSRP, regular, sale, flashsale price fields, not only use case that I specified above.
Thank you.
Hi, I think the usecase is now pretty well defined and that it needs to be discussed with other instantsearch.js core members. At first yes, I feel like this would be a good addition.
cc @bobylito and maybe @pixelastic? What do you think of this proposal:
As a user, I want to be able to have a single range slider that would refine on multiple attributes at the same time using the same range.
When computing the ranges dynamically, we would take the min and max of all the specified attributes
The use case being, a website where depending on their profile, users would have multiple prices for single objects. Some of those objects, given the price range might have one price group that is in range, some might not.
As for querying, this could be handed via secured API keys, but you still need to refine on multiple prices at some point so that's not a solution.
As for the API, it would look like:
rangeSlider({
attributes: ['..', '..'],
});
The use-case seems to make sense. I still have trouble correctly figuring out in my head how a "sort by price" ordering of the results will look, when filtering with on multiple price attributes.
Also, wouldn't it be possible achieve the same effect by adding new attributes to the records? Like price_min
and price_max
being the min and max values of all the price
, price_groupA
, price_groupB
and price_groupC
, and we do the filtering on those values. Granted, we would need to compute these min/max for all possible combination of groups, which will quickly be cumbersome.
Overall I think it makes sense to integrate it in instantsearch (even if I'm not sure how to do it), but it will require some real-life testing to make sure it solves more issue than it creates (surprising results).
My 2cts :)
Thanks for summing that up @vvo, I was a bit lost. It makes sense as a solution 👍 . Only thing that might be bothering is where to provide this widget. Is it a common enough use case to be in the main set of widgets?
The use-case seems to make sense. I still have trouble correctly figuring out in my head how a "sort by price" ordering of the results will look, when filtering with on multiple price attributes.
That I did not think about it, I guess both features are not compatible (sortBy, rangeSlider on multiple attributes)
Also, wouldn't it be possible achieve the same effect by adding new attributes to the records? Like price_min and price_max being the min and max values of all the price, price_groupA, price_groupB and price_groupC, and we do the filtering on those values. Granted, we would need to compute these min/max for all possible combination of groups, which will quickly be cumbersome.
Indeed that's also a possible solution to this, @virtuman do you think you would be able to compute such attributes? That would mean, for every product, compute the possible price groups min and max values.
Only thing that might be bothering is where to provide this widget. Is it a common enough use case to be in the main set of widgets?
I was up for just upgrading the rangeSlider widget and allow to provide multiple attributes instead of just one. That would trigger a behavior change in the widget.
We could also create a different widget for that, but then we need to name it and reuse the internal widget.
Seems like support for multiple attributes in slider widget won't cause any issues for the existing users, since they already have only 1 attribute specified as is, and it would enhance their ability to add searching by multiple fields.
It seems like it would be a much more flexible option to be able to just define a set of fields, or use array of key-values such as I was proposing above:
attributeName: ['price', 'sale_price', 'regular_price', 'msrp', 'price_codeA', 'price_codeB']
but maybe with a little twist, to support key-value array, such as:
id: 123,
title: "apple ipad 32gb black",
offers: {
offer1: 150,
offer333: 100,
off3z: 200
}
price_sale: 180,
price_retail: 180,
price_msrp: 160,
price_wholesale: 150
}
attributeName: ['offers.*', 'price_sale', 'price_retail', 'price_msrp' , 'price_wholesale']
Computing something would require existing users to have to modify their indexing logic, and it could be a little more complicated for them to adapt these new features, while adding a single attributes property would make it so much easier.
Thanks
Hi @virtuman thanks again for getting back here. Your insights are very valuable. For now I would recommend you to go the custom widget way: https://community.algolia.com/instantsearch.js/documentation/#custom-widgets
Untill we reach a point where this is available natively. No ETA thought, sorry
That's unfortunate. Can you give us some pointers into things that we should consider for this type of implementation - any high or low level details would probably be very helpful
Thanks
I would recommend you to have a look at the helper documentation: https://community.algolia.com/algoliasearch-helper-js/
Internally, the range widget configures the helper here: https://github.com/algolia/instantsearch.js/blob/b6b42d51809c329ec0375e8ddbac2cc99c60fada/src/widgets/range-slider/range-slider.js#L102
Then it will refine the helper here: https://github.com/algolia/instantsearch.js/blob/b6b42d51809c329ec0375e8ddbac2cc99c60fada/src/widgets/range-slider/range-slider.js#L148
You should read a bit that code then create a new widget or hack the current one (we have a simple dev environement in the repository: https://github.com/algolia/instantsearch.js/#development-workflow)
This is how you could achieve this.
Closing this issue, guidance on achieving this using a custom widget has been provided.