appbaseio / reactivesearch

Search UI components for React and Vue
https://opensource.appbase.io/reactivesearch
Apache License 2.0
4.9k stars 467 forks source link

FeatureRequest: The ability to have multiple sorts per sortOption #256

Closed davidklebanoff closed 4 years ago

davidklebanoff commented 6 years ago

Issue Type: Enhancement

Description: My apologies if this already exists in some way; if it does I could not find it.

I'm looking for a way to have more advanced sort options. Specifically, the ability for a sortOption to support multiple sorts, executed in the order declared.

For example, suppose we wanted two search options, Best Match which sorts by the relevance score, and Rating which sorts by the rating field and secondarily sorts by the relevance score.

Here's a crude mockup:

<ResultCard
    react={{
        "and": ["PriceFilter", "SearchFilter"]
    }}
    onData={this.onData}
    sortOptions={[
        {
            label: "Best Match",
            dataField: "_score",
            sortBy: "desc"
        },
        {
            label: "Rating",
            and: {[
                {
                    dataField: "rating",
                    sortBy: "desc"
                },
                {
                    dataField: "_score",
                    sortBy: "desc"
                }
            ]}
    }]
/>

This feature request applies to all the result components: ResultList, ResultCard, and ReactiveList.

ElasticSearch sort docs

metagrover commented 6 years ago

This is pretty interesting. Thoughts @siddharthlatest?

davidklebanoff commented 6 years ago

Bump. @siddharthlatest. :)

metagrover commented 6 years ago

How about a consistent structure like this:

sortOptions={[
        {
            label: "Best Match",
            sort: { order: "desc", dataField: "_score" },
        },
        {
            label: "Rating",
            sort: [
                { order: "desc", dataField: "_score" },
                { order: "desc", dataField: "rating" },
            ],
        },
]}
davidklebanoff commented 6 years ago

@metagrover That looks great to me!

siddharthlatest commented 6 years ago

@davidklebanoff Imo, doing something like this breaks the current apps that use sortOptions prop. Also, this still misses out certain things: mode, geo_distance sorting, etc. options that ES's sort DSL offers.

One solution (that already works) here is to use the defaultQuery and pass the appropriate sort key to it when the dropdown UI selection changes. This offers a no compromise sorting DSL with some trade-off in having to write a dropdown UI.

axeff commented 6 years ago

@siddharthlatest When I try to put my geo_distance sorting into the setQuery (I'm using ReactiveComponent), the sort part is magically cut out. Query looks like this in my code but if I query = { from: 0, size: 10, query: { bool: { filter: { geo_distance: { distance: '300km', location: [ lon, lat, ], }, }, }, }, sort: { _geo_distance: { location: { lat, lon, }, }, }, };

But if I look into the _msearch headers it is missing: { "query": { "bool": { "must": [ { "bool": { "must": [ { "bool": { "filter": { "geo_distance": { "distance": "300km", "location": [ 8.8311195373535, 47.936405749046 ] } } } } ] } } ] } }, "size": 10 }

I really need _geo_distance to work. Is there any other way to get this done?

axeff commented 6 years ago

I ended up writing my query using axios and not use ReactiveSearch. But my use case will become more complex soon and I would really like to get back to Reactivesearch on Native.

metagrover commented 6 years ago

You can always use ReactiveComponent for your custom needs until we figure out an implementation for this as a part of the library.

Find relevant docs here.

axeff commented 6 years ago

Tried this as well. See the comment above. When using ReactiveComponent with setQuery() the part where I insert sort will not be in my Request Payload.

metagrover commented 6 years ago

Oh then it seems like a bug, I will check on this. Thanks for bringing this up.

axeff commented 6 years ago

@metagrover I updated a codesandbox I once created. As far as I can see there are two POST's in network panel of which the first does have my query including sort, then there is a second one with query:all which will be rendered in ResultCard.

metagrover commented 6 years ago

@axeff The sort query is being applied to myRating component, which is an expected behavior. Sort, size, from and aggs queries don't leak out to other components which are watching the source component. If you wish to apply sort on the result component, you can use defaultQuery prop on the ResultCard. That should work just fine.

Hope that helps!

axeff commented 6 years ago

Ok, got that. And works in example. Thank you. But can I have multiple filters of which one is the geo_distance filter with sort and combine this with other filters?

metagrover commented 6 years ago

Not sure if I understand that but if you can update the ResultCard's defaultQuery dynamically, then the component will fire the updated queries as you change the defaultQuery prop.

bigscratcher commented 5 years ago

Can you add example here, how to sort by _geo_distance. I am struggling with it some time. I can't add it in customQuery in DataSearch or anywhere else, it needs to come after query: {} part as separate section and to get the following in _msearch header: { "from": 0, "size": 10, "query": { "match_all": {} }, "sort": { "_geo_distance": { "pin": "48.1362, 11.5729", "order": "asc", "unit": "km" } } }

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

davidkong0987 commented 4 years ago

Would love to revive this!

danielnolde commented 3 years ago

This would be a very worthwhile addition, i agree, and the issue is still current.

arpithparikh commented 2 years ago

I agree This would be a very worthwhile addition, i agree, and the issue is still current.

I like this propose structure 👍

sortOptions={[ { label: "Best Match", sort: { order: "desc", dataField: "_score" }, }, { label: "Rating", sort: [ { order: "desc", dataField: "_score" }, { order: "desc", dataField: "rating" }, ], }, ]}