The plugin can be configured using the following options:

interface AdvancedSearchInitOptions {
    analytics: false | {
        aggregationWindowMs?: number;
        analyticsStrategy: AnalyticsStrategy;
    };
    bufferUpdates?: boolean;
    collectionPrefix?: string;
    customMappings?: {
        [fieldName: string]: PrimitiveCustomMapping | ObjectCustomMapping;
    };
    documentOverrides?: {
        channelId?: ((context: DocumentContext) => string | Promise<string>);
        channelIds?: ((context: DocumentContext) => string[] | Promise<string[]>);
        collectionIds?: ((context: DocumentContext) => string[] | Promise<string[]>);
        collectionSlugs?: ((context: DocumentContext) => string[] | Promise<string[]>);
        currencyCode?: ((context: DocumentContext) => string | Promise<string>);
        description?: ((context: DocumentContext) => string | Promise<string>);
        enabled?: ((context: DocumentContext) => boolean | Promise<boolean>);
        facetIds?: ((context: DocumentContext) => string[] | Promise<string[]>);
        facetValueIds?: ((context: DocumentContext) => string[] | Promise<string[]>);
        id?: ((context: DocumentContext) => string | Promise<string>);
        inStock?: ((context: DocumentContext) => boolean | Promise<boolean>);
        languageCode?: ((context: DocumentContext) => string | Promise<string>);
        options?: ((context: DocumentContext) => string[] | Promise<string[]>);
        price?: ((context: DocumentContext) => number | Promise<number>);
        priceWithTax?: ((context: DocumentContext) => number | Promise<number>);
        productAssetId?: ((context: DocumentContext) => string | Promise<string>);
        productId?: ((context: DocumentContext) => string | Promise<string>);
        productInStock?: ((context: DocumentContext) => boolean | Promise<boolean>);
        productName?: ((context: DocumentContext) => string | Promise<string>);
        productPreview?: ((context: DocumentContext) => string | Promise<string>);
        productPreviewFocalPoint?: ((context: DocumentContext) => [] | [number, number] | Promise<[] | [number, number]>);
        productVariantAssetId?: ((context: DocumentContext) => string | Promise<string>);
        productVariantId?: ((context: DocumentContext) => string | Promise<string>);
        productVariantName?: ((context: DocumentContext) => string | Promise<string>);
        productVariantPreview?: ((context: DocumentContext) => string | Promise<string>);
        productVariantPreviewFocalPoint?: ((context: DocumentContext) => [] | [number, number] | Promise<[] | [number, number]>);
        sku?: ((context: DocumentContext) => string | Promise<string>);
        slug?: ((context: DocumentContext) => string | Promise<string>);
    };
    externalIndexes?: ExternalIndex<any>[];
    internalCacheTtl?: number;
    licenseKey: string;
    shopApiKeySecret?: string;
    sortableFields?: SortableField[];
    typeSenseClientOptions: ConfigurationOptions;
}

Properties

analytics: false | {
    aggregationWindowMs?: number;
    analyticsStrategy: AnalyticsStrategy;
}

Configure how search analytics are stored. If you want to disable analytics, set this to false.

Type declaration

  • OptionalaggregationWindowMs?: number

    The "debounce" time used in aggregating searches, so that e.g. typing i, ip, ipa, ipad (delay) will only result in "ipad" being logged (when logAnalytics: true is set). This is to avoid logging searches for terms that the user is still typing.

    10000
    
  • analyticsStrategy: AnalyticsStrategy

    The AnalyticsStrategy determines how search analytics are stored and retrieved for analysis.

bufferUpdates?: boolean

If set to true, updates to Products, ProductVariants and Collections will not immediately trigger an update to the search index. Instead, all these changes will be buffered and will only be run via a call to the runPendingSearchIndexUpdates mutation in the Admin API.

This is very useful for installations with a large number of ProductVariants and/or Collections, as the buffering allows better control over when these expensive jobs are run, and also performs optimizations to minimize the amount of work that needs to be performed by the worker.

false
collectionPrefix?: string

An optional prefix string for the Typesense collections that will be created. This can be useful if you are running multiple Vendure instances which share the same Typesense instance, as it allows you to differentiate between the collections created by each instance.

''
customMappings?: {
    [fieldName: string]: PrimitiveCustomMapping | ObjectCustomMapping;
}

Custom mappings allow you to define additional fields which will be indexed in the products index.

AdvancedSearchPlugin.init({
// ...
customMappings: {
reviewRating: {
graphQlType: 'Float',
valueFn: ({ variant }) => variant.product.customFields.reviewRating,
},
reviewCount: {
graphQlType: 'Int!',
valueFn: ({ variant }) => variant.product.customFields.reviewCount,
},
facetValues: {
graphQlType: 'String!',
searchable: true,
hydrateRelations: ['product.facetValues'],
valueFn: ({ variant, languageCode }) =>
variant.product.facetValues
.map((fv) => translateDeep(fv, languageCode).name)
.join(' '),
},
featuredAssetName: {
graphQlType: 'String!',
hydrateRelations: ['product.featuredAsset'],
valueFn: ({ variant }) => variant.product.featuredAsset?.name ?? '',
searchable: true,
},
discountPercentage: {
graphQlType: 'Float',
valueFn: ({ variant }) => variant.customFields?.discountPercentage,
outputFn: (values: number[], groupByProduct: boolean) => {
if (groupByProduct) {
return Math.max(...values);
} else {
return values[0];
}
},
},
},
}),
documentOverrides?: {
    channelId?: ((context: DocumentContext) => string | Promise<string>);
    channelIds?: ((context: DocumentContext) => string[] | Promise<string[]>);
    collectionIds?: ((context: DocumentContext) => string[] | Promise<string[]>);
    collectionSlugs?: ((context: DocumentContext) => string[] | Promise<string[]>);
    currencyCode?: ((context: DocumentContext) => string | Promise<string>);
    description?: ((context: DocumentContext) => string | Promise<string>);
    enabled?: ((context: DocumentContext) => boolean | Promise<boolean>);
    facetIds?: ((context: DocumentContext) => string[] | Promise<string[]>);
    facetValueIds?: ((context: DocumentContext) => string[] | Promise<string[]>);
    id?: ((context: DocumentContext) => string | Promise<string>);
    inStock?: ((context: DocumentContext) => boolean | Promise<boolean>);
    languageCode?: ((context: DocumentContext) => string | Promise<string>);
    options?: ((context: DocumentContext) => string[] | Promise<string[]>);
    price?: ((context: DocumentContext) => number | Promise<number>);
    priceWithTax?: ((context: DocumentContext) => number | Promise<number>);
    productAssetId?: ((context: DocumentContext) => string | Promise<string>);
    productId?: ((context: DocumentContext) => string | Promise<string>);
    productInStock?: ((context: DocumentContext) => boolean | Promise<boolean>);
    productName?: ((context: DocumentContext) => string | Promise<string>);
    productPreview?: ((context: DocumentContext) => string | Promise<string>);
    productPreviewFocalPoint?: ((context: DocumentContext) => [] | [number, number] | Promise<[] | [number, number]>);
    productVariantAssetId?: ((context: DocumentContext) => string | Promise<string>);
    productVariantId?: ((context: DocumentContext) => string | Promise<string>);
    productVariantName?: ((context: DocumentContext) => string | Promise<string>);
    productVariantPreview?: ((context: DocumentContext) => string | Promise<string>);
    productVariantPreviewFocalPoint?: ((context: DocumentContext) => [] | [number, number] | Promise<[] | [number, number]>);
    sku?: ((context: DocumentContext) => string | Promise<string>);
    slug?: ((context: DocumentContext) => string | Promise<string>);
}

It is possible to override the indexed value of the built-in fields on the SearchResult type. For example, let's say you have a customField which stores a "sale price" which you want to use in your search results. Here's how you can configure it:

AdvancedSearchPlugin.init({
// ...
documentOverrides: {
priceWithTax: ({ variant }) => variant.customFields.salePrice,
},
}),
externalIndexes?: ExternalIndex<any>[]

Allows you to define additional external indexes which can be queried alongside the main product index.

internalCacheTtl?: number

When searching the product index, data on related Collections and Facets is cached for performance reasons. This setting allows you to set the TTL (how long a cached item lives before it must be refreshed from the database) for this cache.

A higher value will reduce the number of database queries made during search, but may result in stale data being returned.

30000
licenseKey: string

The license key can be found in your Vendure Hub account at https://vendure.io/account/licenses, and then clicking on the installation instructions for this plugin's license

shopApiKeySecret?: string

A secret string used to encrypt the Shop API key in the database. When this is set, a new customField will be defined on the GlobalSettings entity, which is used to store the encrypted shop API key.

sortableFields?: SortableField[]

Allows you to define additional ways to sort the search results.

AdvancedSearchPlugin.init({
// ...
sortableFields: [
// Here we are specifying that the 'sku' field
// should also be sortable
{ name: 'sku' },
// Assuming we have defined a customMapping for reviewRating
// (as in the example above), we can also make this sortable.
{
// This name must match the field name internally in TypeSense,
// which, for customMappings is always of the format
// `customMapping_<name>`.
name: 'customMapping_reviewRating',
// We can alias this with a more friendly name that will be used
// in the GraphQL API "sort" input.
alias: 'rating'
}
],
});
typeSenseClientOptions: ConfigurationOptions

The configuration options for the Typesense client.

 typeSenseClientOptions: {
apiKey: process.env.TYPESENSE_API_KEY,
nodes: [
{
host: process.env.TYPESENSE_HOST,
port: 8108,
protocol: 'http',
},
],
},