Data Aware UI components

One of the key ideas behind Reactive Search and Reactive Maps is the abstraction of a query interface.

The UI components are already associated with the data queries. For instance,

  • SingleList and MultiList components create a exact term match query based on the selected items.
  • A RangeSlider component creates a numeric range query based on the selected start and end values.

Components rely on the dataField prop for selecting the database field on which the query needs to be applied.

However, there are cases where you would wish to override the associated query with your own.

When to use Custom Query

customQuery is used to change the component's behavior for its subscribers. It gets triggered after an interaction on the component. Every component is shipped with a default behavior i.e. selecting a city on the SingleList component generates a term query. If you wish to change this behavior i.e. maybe perform additional query besides term query or do something else altogether, you can use customQuery prop.

Copy
:customQuery = `() => ({
    query: {
        term: {
                user : "Kimchy"
            }
        }
    })
`

Defining a Custom Query

Each component has a customQuery prop that accepts a function. The function can return an object in which you can define a query key(to modify the actual query) along with the query options(to add the query options in the query generated by ReactiveSearch) compatible with Elasticsearch Query DSL. Here is a simple query object that applies a match query.

Copy
<template>
  <search-box
   :customQuery="customQuery"
   ...
  />
</template>
<script>
  export default {
    name: "app",
    methods: {
      customQuery() {
        return {
          "query": {
            "match": { "fieldName": "text to match" }
          }
        }
      }
    }
  }
</script>

Here is another example that applies a match_phrase_prefix query.

Copy
<template>
  <search-box
   :customQuery="customQuery"
   ...
  />
</template>
<script>
  export default {
    name: "app",
    methods: {
      customQuery() {
        return {
          "query": {
            "match_phrase_prefix": {
              "fieldName": {
                "query": "hello world",
                "max_expansions": 10
              }
            }
          }
        }
      }
    }
  }
</script>

You can also define the query options in custom query:

Copy
<template>
  <search-box
   :customQuery="customQuery"
   ...
  />
</template>
<script>
  export default {
    name: "app",
    methods: {
      customQuery() {
        return {
          "timeout": "1s",
          "query": {
            "match_phrase_prefix": {
              "fieldName": {
                "query": "hello world",
                "max_expansions": 10
              }
            }
          },
        }
      }
    }
  }
</script>

When to use Default Query

defaultQuery is ideally used with data-driven components to impact their own data. It is meant to modify the default query which is used by a component to render the UI.

Some of the valid use-cases are:

  • To modify the query to render the suggestions in search components.
  • To modify the aggregations in list components.
  • To modify the default results in ReactiveList component.

For example, in a SingleList component showing list of cities you may only want to render cities belonging to India.

Copy
:defaultQuery = `() => ({
        query: {
            terms: {
                country: [ "India" ]
            }
        }
    }
})`

Defining a Default Query

Some components have a defaultQuery prop that accepts a function which has the same specifications as customQuery.DefaultQuery is used to apply the query on the source component. Unlike customQuery, It doesn't get leaked to other components. It's as if you create an internal component and apply the defaultQuery on it. Ideally, you would use this with components that are data-driven.

Copy
<template>
  <single-list
   :defaultQuery="defaultQuery"
   ...
  />
</template>
<script>
  export default {
    name: "app",
    methods: {
      defaultQuery() {
        return {
           "query": {
              "terms": {
                  "country": [ "India" ]
              }
          }
        }
      }
    }
  }
</script>

You can also define the query options in custom query:

Copy
<template>
  <single-list
   :defaultQuery="defaultQuery"
   ...
  />
</template>
<script>
  export default {
    name: "app",
    methods: {
      defaultQuery() {
        return {
          "timeout": "1s",
          "query": {
              "terms": {
                  "country": [ "India" ]
              }
          },
        }
      }
    }
  }
</script>

Not familiar to Elasticsearch?

You need to write a custom query but haven't worked with Elasticsearch. Okay, as a super quick primer, Elasticsearch is a data store search engine with a NoSQL JSON data model.

The docs link above is a good way to explore Elasticsearch in depth. Another alternative to get started with the query syntax is Mirage, a GUI for composing Elasticsearch queries.