typesense / typesense-instantsearch-adapter

A JS adapter library to build rich search interfaces with Typesense and InstantSearch.js
MIT License
414 stars 64 forks source link

Multi-index search -> queryby can not be individually chosen #38

Closed reinoldus closed 3 years ago

reinoldus commented 3 years ago

Description

I would like to implement a multi index search using the following component from instantsearch: https://www.algolia.com/doc/api-reference/widgets/index-widget/vue/

The issue is: It only works if both indexes share the same attribute you want to query on, if you want to query e.g. name in index A and body in index B then you'd have to instantiate two search clients which would also result in two requests to the server.

It would be great if we could use to overwrite queryBy or add something like this to additonalSearchParameters:

      additionalSearchParameters: {
        "index A": {queryBy: this.queryBy,},
        "index B": {queryBy: this.queryBy,}
      },

Steps to reproduce

The following snippet should help to build a sample app

<template>
  <ais-instant-search :search-client="searchClient" :index-name="indexName">
    <b-form-input v-model="query" placeholder="Search"></b-form-input>
    <search-debounced-search-box :query="query"></search-debounced-search-box>
    <ais-index index-name="index_2">
      <ais-hits v-if="query || initialResults">
        <template slot-scope="{ items }">
          <div
            v-for="item in items"
            :key="item.objectID"
            class="pointer py-3"
            @click="query = undefined"
          >
            <slot :item="item"</slot>
          </div>
        </template>
      </ais-hits>
    </ais-index>
    <ais-hits v-if="query || initialResults">
      <template slot-scope="{ items }">
        <div
          v-for="item in items"
          :key="item.objectID"
          class="pointer py-3"
          @click="query = undefined"
        >
          <slot :item="item"></slot>
        </div>
      </template>
    </ais-hits>
  </ais-instant-search>
</template>

<script>
import {
  AisInstantSearch,
  AisHits,
  AisIndex
} from 'vue-instantsearch'

import TypesenseInstantSearchAdapter from 'typesense-instantsearch-adapter'
import SearchDebouncedSearchBox from '@/components/search/search-debounced-search-box'

export default {
  components: {
    SearchDebouncedSearchBox,
    AisInstantSearch,
    AisHits,
    AisIndex
  },
  props: {
    indexName: {
      type: String,
      default() {
        return 'x'
      },
    },
    queryBy: {
      type: String,
      default() {
        return 'name'
      },
    },
    initialResults: {
      type: Boolean,
      default() {
        return false
      },
    },
  },
  data() {
    const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
      server: {
        apiKey: 'xxxxxxxxxxxxxxxxxxxx', // Be sure to use the search-only-api-key
        nodes: [
          {
            host: 'xxxxxxxxxxxxxxxxxxxx',
            port: '443',
            protocol: 'https',
          },
        ],
      },
      // The following parameters are directly passed to Typesense's search API endpoint.
      //  So you can pass any parameters supported by the search endpoint below.
      //  queryBy is required.
      additionalSearchParameters: {
        queryBy: this.queryBy,
      },
    })
    const searchClient = typesenseInstantsearchAdapter.searchClient
    // searchClient.widget.configure()
    return {
      searchClient,
      query: this.initialQuery,
    }
  },
}
</script>

Expected Behavior

I can set the queryBy-parameter for each index separately

Actual Behavior

Querying only works if both indexes share the attribute e.g: "name"

streetcolor commented 3 years ago

Hi there,

Same problem with instantsearch.js. I need to fetch data in two indexes (category and product).

The Brand facet is configured for Product Index but it's irrelevant for Category Index.

With Algolia, we can use index widget => https://www.algolia.com/doc/api-reference/widgets/index-widget/js/ We build a kind of nested widget. It works like a charm (take a look to the screen), but with type sense i'm facing an issue...

My console returns this error : Error: 404 - Could not find a facet field namedbrandin the schema.

Expected Behavior (with Algolia)

Capture d’écran 2021-04-19 à 22 58 46
jasonbosco commented 3 years ago

@reinoldus @streetcolor Thank you for bringing this up. I just added support for collection/index-specific settings in a pre-release version of the adapter: v1.2.0-0

Here are instructions on how to use it: https://github.com/typesense/typesense-instantsearch-adapter/tree/v1.2.0-0#index

Could you give it a shot and let me know if you run into any issues?

streetcolor commented 3 years ago

Hi Jasonbosco,

Unfortunately, your patch doesn't fix issue. I need to replace facet_by which is sent in the request.

Capture d’écran 2021-05-07 à 23 48 34

Best regards,

jasonbosco commented 3 years ago

@streetcolor facet_by is controlled by the InstantSearch library (not the adapter), when you use any of the filter widgets like RefinementList, RangeSlider, etc. So facet_by can't be overridden manually in the adapter using additionalSearchParameters - InstantSearch will just ignore it and use what you've configured in the widgets.

So you'd have to use the index widget and scope other filter widgets within it, and then InstantSearch will take care of setting facet_by automatically for you, based on the widget's attribute field.

Could you share a minimal code snippet that shows how you've configured the widgets?