# Enable Filters for Extended Fields

**Category:** Features/Enrich/Data Extension

## Guide

This article explains how to enable filters on your extended fields.

Once enabled, you'll see your extended fields when you click **Filter**:

![Filter button](./data-extension-filter.png)

Filters will be automatically displayed for your extended fields based on the following mapping:

* **Boolean**: Radio button
* **Number**: Number range
* **Dates**: Date picker
* **Strings** (including URL and files): Not supported

### Before you begin

Make sure that you have:

* A Patterns [`Table`](./?path=%2Fstory%2Fbase-components-collections-table-table--table) component.
* A server configured to [support data extensions](https://dev.wix.com/docs/rnd-general/articles/open-platform/data-extensions/data-extensions-101#backend).
* Followed the [steps to display extended fields](./?path=/story/features-enrich-data-extension--display-extended-fields).

### Step 1 | Expose a Nile/Search endpoint

1. In your `BUILD.bazel` file, add a [`search` macro definition](https://github.com/wix-private/search/blob/master/nile/README.md#macro-definition-prime_app) to your `prime_app()`. For example:

    ```javascript
    prime_app(
        // ..
        search = {
            "pii": False,
            "tenancy": "Instance",
            "schemas": {
                "poc": {
                    "cluster": "es-poc",
                },
            },
        }
        // ..
    )
    ```

1. In your proto, add a search API including search, filter, sort and aggregation capabilities. For example:

    ```javascript
    rpc SearchDummyEntities (SearchDummyEntitiesRequest) returns (SearchDummyEntitiesResponse) {
        option (google.api.http).post = "/v1/dummy-entities/search";
        option (wix.api.crud) = {
            method: SEARCH
            search_options: {
            items_field: 'dummy_entities'
            paging: {
                type: CURSOR
            },
            wql: {
                pattern: {
                operator: ALL_APPLICABLE_OPERATORS
                sort: BOTH
                field: "created_date"
                field: "updated_date"
                }
            }
            }
        };
    }
    ```

> **Note:** The source of truth for this information is in the [Nile/Search README](https://github.com/wix-private/search/blob/master/nile/README.md#data-extensions--extended-fields).

### Step 2 | Support filter aggregations over your entity

1. Mark your extensible entity as filterable.

    ```javascript
    option (wix.api.entity) = {
      fqdn: "wix.search.test.v1.product",
      app_def_id: "00000000-0000-0000-0000-000000000000"
      extensible: {
        filterable: true
      }
    }
    ```

1. Apply Schema changes to production via [Dev Portal](https://wix-bo.com/dev/projects) in the **Nile Search** tab.

    ![Nile search tab](./nile-search-tab.png)

### Step 3 | Edit your Table component

In your table component:

1. Import the `transformCustomFiltersToWQL` and `transformSortToWQL` helper functions.

    ```javascript
    import { transformCustomFiltersToWQL, transformSortToWQL } from '@wix/patterns';
    ```

1. Use the helper functions in your `fetchData` function. For example:

    ```diff
    const state = useTableCollection({
        fqdn: 'wix.cairo.dummyservice.v1.dummy_entity',
        toExtendedFields: (item) => item.extendedFields,
        fetchData: async ({ search = '', filters, sort }) => {
            const querySearch: SearchDummyEntitiesRequest = {
            search: {
    +         sort: transformSortToWQL(sort),
                filter: {
    +           ...transformCustomFiltersToWQL(state, filters),
                name: { $startsWith: search },
                },
            },
            };
            // ...
        },
        // ...
    });
    ```

1. Mark the data extension component `filterable`.

    ```diff
    }
        // ..
    />
    ```

### See also

* [Data Extension Overview](./?path=/story/features-enrich-data-extension--data-extension-overview)
* [Allow Users to Add Extended Fields](./?path=/story/features-enrich-data-extension--allow-users-to-add-extended-fields)


## Examples

### Filter by a custom field

This example demonstrates how to enable filtering capabilities for custom fields by configuring your FQDN to support filters.

```tsx
import React from 'react';
import { CollectionPage } from '@wix/patterns/page';
import {
  DataExtension,
  useTableCollection,
  Table,
  transformCustomFiltersToWQL,
  transformSortToWQL,
  CursorQuery,
  useSelector,
} from '@wix/patterns';
import {
  Contact,
  SearchContactsRequest,
} from '@wix/ambassador-contacts-v5-contact/types';
import { searchContacts } from '@wix/ambassador-contacts-v5-contact/http';
import { useHttpClient } from '@wix/yoshi-flow-bm';

function WithFiltersSupport() {
  const httpClient = useHttpClient();

  const state = useTableCollection<Contact>({
    queryName: 'cool-table-name',
    paginationMode: 'cursor',
    fqdn: 'wix.patterns.dummyservice.v1.dummy_entity',
    toExtendedFields: (item) => item.extendedFields,
    persistQueryToUrl: true,

    fetchData: async ({
      search = '',
      filters,
      sort,
      cursor,
      limit,
    }: CursorQuery) => {
      const querySearch: SearchContactsRequest = {
        search: {
          search: { expression: search, fields: ['name'] },
          cursorPaging: { limit, cursor },
          sort: transformSortToWQL(sort),
          filter: {
            ...transformCustomFiltersToWQL(state, filters),
            name: { $startsWith: search },
          },
        },
      };
      return await httpClient
        .request(searchContacts(querySearch))
        .then(({ data: { contacts, pagingMetadata } }) => ({
          items: contacts || [],
          total: pagingMetadata?.total,
          cursor: pagingMetadata?.cursors?.next,
        }));
    },
    fetchErrorMessage: ({ err }) => `Error: ${err}`,
    itemKey: (item) => item.id!,
    itemName: (item) => item.name?.first || '',
  });

  // !!! DO NOT USE THIS CODE - IT IS FOR DEMONSTRATION PURPOSES ONLY !!!
  const items = useSelector(
    () => state.toolbar.customColumnsState?.columnsCollection.result.items,
  );
  React.useEffect(() => {
    const columns = items?.filter((item) =>
      ['checkbox', 'datetime', 'decimal']
        .map((field) => `extendedFields.namespaces._user_fields.${field}`)
        .includes(item.id),
    );
    columns?.forEach((column) => {
      state.toolbar.customColumnsState?.onColumnCheckboxToggle(column);
    });
  }, [items?.length]);
  // **************************************************************** //

  return (
    <CollectionPage height="400px">
      <CollectionPage.Header title={{ text: 'Contacts' }} />
      <CollectionPage.Content>
        <Table
          state={state}
          horizontalScroll
          dataExtension={<DataExtension filterable disableUserDefinedWriting />}
          columns={[
            {
              id: 'name',
              title: 'Name',
              width: '250px',
              render: (item) => item.name,
            },
          ]}
        />
      </CollectionPage.Content>
    </CollectionPage>
  );
}
```

