# Elastic sort by in stock

**URL:** <https://forum.litium.com/t/elastic-sort-by-in-stock/2255>\
**Category:** Questions\
**Tags:** litium-7\
**Created:** [October 18, 2021, 2:22pm UTC](https://forum.litium.com/t/elastic-sort-by-in-stock/2255 "2021-10-18T14:22:23Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![victaxel](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/victaxel/32/159_2.png) [@victaxel](https://forum.litium.com/u/victaxel)\
**Post date:** [October 18, 2021, 2:22pm UTC](https://forum.litium.com/t/elastic-sort-by-in-stock/2255/1 "2021-10-18T14:22:23Z")

</div>

Hi,

I need some assistance with sorting elastic search results by in stock for all available sorting methods. The case would be something like:

“Sort by desired sorting method, then put all out of stock products at the end of the list of hits”

Is this possible?

Litium version: 7.6

---

<div class="post-metadata">

**Author:** ![NilsN](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/nilsn/32/302_2.png) [@NilsN](https://forum.litium.com/u/NilsN)\
**Post date:** [October 19, 2021, 11:12am UTC](https://forum.litium.com/t/elastic-sort-by-in-stock/2255/2 "2021-10-19T11:12:57Z")

</div>

If you’ve added the stock to the `ProductDocument` you can just add a sorting for in `BuildSortings(...)`. By having it first in the additional sortings it would push unavailable items to the end.

```auto
s = s
	.Descending(x => x.InStock)
	.Field(f => searchQuery.SortDirection == SortDirection.Ascending
	? f.Field(x => x.Name.Suffix("keyword")).Ascending()
	: f.Field(x => x.Name.Suffix("keyword")).Descending())
	.Ascending(x => x.ArticleNumber);

```

(`InStock` is a boolean in this example)

---

<div class="post-metadata">

**Author:** ![patric.forsgard](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/patric.forsgard/32/10_2.png) [@patric.forsgard](https://forum.litium.com/u/patric.forsgard)\
**Post date:** [October 19, 2021, 12:33pm UTC](https://forum.litium.com/t/elastic-sort-by-in-stock/2255/3 "2021-10-19T12:33:05Z")

</div>

Things to think of during implementation

1. Don’t store de actual quantity in search index, instead have a calculated property (of field on the product) that contains if they are in stock as in the example above.
2. Sorting on “In stock” may break other sorting operations, example hits by score for free text search that in the most cases need to be the first sort field.
3. Instead of sorting it may work to boost the relevance of the search result depend on a field, se examples on [elasticsearch - How can we use exists query in tandem with the search query? - Stack Overflow](https://stackoverflow.com/a/41589241), that may give similar result but not break the sorting.

---

<div class="post-metadata">

**Author:** ![victaxel](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/victaxel/32/159_2.png) [@victaxel](https://forum.litium.com/u/victaxel)\
**Post date:** [October 19, 2021, 12:44pm UTC](https://forum.litium.com/t/elastic-sort-by-in-stock/2255/4 "2021-10-19T12:44:14Z")

</div>

I was thinking I’d add a boolean to the productdocument depending on whether or not there is a instockquantity \> 0 on any of the variants and then use Nils’ example sort. That would work, right?

I’m almost done with the above. I’ll try it and see how free text search behaves.

Thank you both!

---

<div class="post-metadata">

**Author:** ![adam.clettborn](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/adam.clettborn/32/956_2.png) [@adam.clettborn](https://forum.litium.com/u/adam.clettborn)\
**Post date:** [October 25, 2021, 12:35pm UTC](https://forum.litium.com/t/elastic-sort-by-in-stock/2255/5 "2021-10-25T12:35:31Z")

</div>

Hi, I picked up this issue from @victaxel.

Could you give an example in code for option 3? I can’t get it to work, all items that are not in stock are excluded from the result, using the following code:

```auto
var countryId = _requestModelAccessor.RequestModel.CountryModel.Country.Id;
allQueries.Add(qc.Bool(b => b.Should(bs => bs.Exists(e => e.Field(f => f.InStock[countryId]).Boost(1)))));

```

InStock is a `Dictionary<string, bool>` where key is country id and value is stock status boolean (true = in stock, false = out of stock).

I also tried with the following code:

```auto
var countryId = _requestModelAccessor.RequestModel.CountryModel.Country.Id;
allQueries.Add(qc.Bool(b => b.Should(bs => bs.Term(t => t.InStock[countryId], true, 1))));

```

This also results in products that are not in stock to be excluded from the result.  
I’m doing this in the `BuildQuery`-method in `ProductSearchServiceDecorator`.

---

<div class="post-metadata">

**Author:** ![patric.forsgard](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/patric.forsgard/32/10_2.png) [@patric.forsgard](https://forum.litium.com/u/patric.forsgard)\
**Post date:** [October 25, 2021, 3:23pm UTC](https://forum.litium.com/t/elastic-sort-by-in-stock/2255/6 "2021-10-25T15:23:56Z")

</div>

I haven’t tested this my self but I think you need to boost more than with `1` because that is the default-value.

If using `exists` you probably need to set the value to `true` for the records that exists, all the other should not have any value there at all.

Also dependent on how the field are indexed (object or nested) the result can be different.

---

<div class="post-metadata">

**Author:** ![adam.clettborn](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/adam.clettborn/32/956_2.png) [@adam.clettborn](https://forum.litium.com/u/adam.clettborn)\
**Post date:** [October 26, 2021, 6:03am UTC](https://forum.litium.com/t/elastic-sort-by-in-stock/2255/7 "2021-10-26T06:03:59Z")

</div>

I’ve tried with both exists and just match the value to “true”, both filters out all out of stock products. When I used exists I only set the value if the product had stock.  
I also tried boosting more than 1, such as 100 or 20, without any change. I’m lost here…

This is the property in ProductDocument, no attributes:  
`public Dictionary<string, bool> InStock { get; set; }`

---

<div class="post-metadata">

**Author:** ![NilsN](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/nilsn/32/302_2.png) [@NilsN](https://forum.litium.com/u/NilsN)\
**Post date:** [October 27, 2021, 2:27pm UTC](https://forum.litium.com/t/elastic-sort-by-in-stock/2255/8 "2021-10-27T14:27:42Z")

</div>

The documentation on [Exists](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html) suggests that it will only retrieve documents that has a value for that field in the index, so if you leave it out when it’s not in stock it makes sense that you’re not seeing it.

Could you maybe add a weight to documents where the `InStock` property is true?

```auto
var countryId = _requestModelAccessor.RequestModel.CountryModel.Country.Id;
allQueries.Add(qc.FunctionScore(fs => fs
	.Functions(fu => fu
		.Weight(w => w
			.Weight(100)
			.Filter(wf => wf
				.Term(t => t.InStock[countryId], true))))));

```

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex030/uploads/litium/original/1X/12eddac3b8b661de1db86af10ac8151b571e6fb9.png) [@system](https://forum.litium.com/u/system)\
**Post date:** [November 24, 2021, 2:28pm UTC](https://forum.litium.com/t/elastic-sort-by-in-stock/2255/9 "2021-11-24T14:28:21Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
