Faceted Search with multiple selections from one facet

I'm trying to implement a faceted search on my website that allows users to select multiple facets within a group, but it also needs to filter out irrelevant options in other facets based on selections. Here's the scenario:

  • I have four active products, all categorized under 'Thermostats'.
  • Users can filter these products by two facets: price (with options "$20 - $50", "$50 - $100", "$100 - $200", "$200 - $500") and product type (with options "Air Exchanger Accessories", "Digital Thermostat").
  • If a user selects the "Air Exchanger Accessories" facet, only one product matches, priced between "$200 - $500". This selection should dynamically adjust the available price options to just "$200 - $500", while still displaying "Digital Thermostat" as an option for potential multi-selection.

I'm unsure if this can be achieved with a single query or if multiple queries and subsequent filtering are required.

Here is example data:

POST /_bulk
{"index": { "_index": "facet-test" }}
{"allAttributes":[{"atrKeys":["5"],"code":"price","type":"Price","values":["$200 -$500"]},{"atrKeys":["by1"],"code":"product_specifications","id":1329,"type":"Product Specifications","values":["Air Exchanger Accessories"]},{"atrKeys":["ecc"],"code":"product_category","id":14,"type":"Product Category","values":["Thermostats"]}],"isActive":true,"keyAttributes":["ecc","by1", "5"],"name":"Product 1"}
{"index": { "_index": "facet-test" }}
{"allAttributes":[{"atrKeys":["4"],"code":"price","type":"Price","values":["$100 - $200"]},{"atrKeys":["9w9"],"code":"product_specifications","id":1329,"type":"Product Specifications","values":["Digital Thermostat"]},{"atrKeys":["ecc"],"code":"product_category","id":14,"type":"Product Category","values":["Thermostats"]}],"isActive":true,"keyAttributes":["ecc","9w8", "4"],"name":"Product 1"}
{"index": { "_index": "facet-test" }}
{"allAttributes":[{"atrKeys":["3"],"code":"price","type":"Price","values":["$50 - $100"]},{"atrKeys":["9w9"],"code":"product_specifications","id":1329,"type":"Product Specifications","values":["Digital Thermostat"]},{"atrKeys":["ecc"],"code":"product_category","id":14,"type":"Product Category","values":["Thermostats"]}],"isActive":true,"keyAttributes":["ecc","9w8", "3"],"name":"Product 1"}
{"index": { "_index": "facet-test" }}
{"allAttributes":[{"atrKeys":["2"],"code":"price","type":"Price","values":["$20 - $50"]},{"atrKeys":["9w9"],"code":"product_specifications","id":1329,"type":"Product Specifications","values":["Digital Thermostat"]},{"atrKeys":["ecc"],"code":"product_category","id":14,"type":"Product Category","values":["Thermostats"]}],"isActive":true,"keyAttributes":["ecc","9w8", "2"],"name":"Product 1"}

Here is an example query that gets me close to what I want, however the invalid price options still appear in the aggregation.

POST /facet-test/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "isActive": true
          }
        },
        {
          "terms": {
            "keyAttributes": [
              "ecc"
            ]
          }
        }
      ]
    }
  },
  "post_filter": {
    "bool": {
      "must": {
        "term": {
          "keyAttributes": "by1"
        }
      }
    }
  },
  "size": 0,
  "from": 0,
  "aggs": {
    "price": {
      "nested": {
        "path": "allAttributes"
      },
      "aggs": {
        "price": {
          "filter": {
            "bool": {
              "must": [
                {
                  "term": {
                    "allAttributes.code": "price"
                  }
                }
              ]
            }
          },
          "aggs": {
            "options": {
              "terms": {
                "field": "allAttributes.values",
                "size": 100,
                "order": {
                  "_term": "asc"
                }
              },
              "meta": {
                "name": "Price",
                "description": "This is the price",
                "inputType": "checkbox",
                "priority": 1,
                "units": "",
                "tooltipIsLarge": ""
              }
            }
          }
        }
      }
    },
    "attributes": {
      "nested": {
        "path": "allAttributes"
      },
      "aggs": {
        "1329": {
          "filter": {
            "bool": {
              "must": [
                {
                  "term": {
                    "allAttributes.id": "1329"
                  }
                },
                {
                  "term": {
                    "allAttributes.code": "product_specifications"
                  }
                }
              ]
            }
          },
          "aggs": {
            "options": {
              "terms": {
                "field": "allAttributes.values",
                "size": 100,
                "order": {
                  "_term": "asc"
                }
              }
            }
          }
        }
      }
    }
  }
}

The result is:

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  },
  "aggregations": {
    "price": {
      "doc_count": 12,
      "price": {
        "doc_count": 4,
        "options": {
          "meta": {
            "tooltipIsLarge": "",
            "name": "Price",
            "description": "This is the price",
            "inputType": "checkbox",
            "units": "",
            "priority": 1
          },
          "doc_count_error_upper_bound": 0,
          "sum_other_doc_count": 0,
          "buckets": [
            {
              "key": "$100 - $200",
              "doc_count": 1
            },
            {
              "key": "$20 - $50",
              "doc_count": 1
            },
            {
              "key": "$200 -$500",
              "doc_count": 1
            },
            {
              "key": "$50 - $100",
              "doc_count": 1
            }
          ]
        }
      }
    },
    "attributes": {
      "1329": {
        "doc_count": 4,
        "options": {
          "doc_count_error_upper_bound": 0,
          "sum_other_doc_count": 0,
          "buckets": [
            {
              "key": "Air Exchanger Accessories",
              "doc_count": 1
            },
            {
              "key": "Digital Thermostat",
              "doc_count": 3
            }
          ]
        }
      },
      "doc_count": 12
    }
  }
}