# Search

In Forest Admin, pages which show lists of records have a free-text search widget on top of them.

![A search bar on the main list-view](https://3861847666-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9UN5oBJhgzLadOqi7jx6%2Fuploads%2Fgit-blob-1de838b0f8d51d6fe8b96b33cabe8079458219ea%2Fsearch-bar.png?alt=media)

### Search modes

Two search modes are supported: normal and extended.

* All searches start by being a "normal search".
* If the result the user is looking for is not found, it is possible to trigger an extended search from the user interface.

![Extended search call to action](https://3861847666-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9UN5oBJhgzLadOqi7jx6%2Fuploads%2Fgit-blob-56fcdf4b99efedbae8672929074a450c86f5101c%2Fsearch-bar-extended.png?alt=media)

### Default behavior

When not defined otherwise by the [data source](https://docs.forestadmin.com/developer-guide-agents-nodejs/~/revisions/RIg7Xt85Z2LyzUxn7V93/data-sources/connection), the search behavior is to attempt to search within columns of the collection (in normal mode), or columns of the collection of direct relations (in extended mode).

By default, Forest Admin will search only on some columns, depending on their respective types.

| Column Type | Default search behavior                                                |
| ----------- | ---------------------------------------------------------------------- |
| Enum        | Column is equal to the search string (case-insensitive)                |
| Number      | Column is equal to the search string (if the search string is numeric) |
| String      | Column contains the search string (case-insensitive)                   |
| Uuid        | Column is equal to the search string                                   |
| Other types | Column is ignored by the default search handler                        |

### Customization

You may want to change how the search bar behaves in your admin panel.

For instance:

* Search only on the columns which are relevant to your use case.
* Use full-text indexes of your data (i.e Postgres `tsquery` and `tsvector`, Algolia, Elastic search, ...)

To customize the search bar, you must define a handler that returns a [`ConditionTree`](https://docs.forestadmin.com/developer-guide-agents-nodejs/~/revisions/RIg7Xt85Z2LyzUxn7V93/under-the-hood/queries/filters#condition-trees).

#### Making the search case-sensitive by default

In this example, we use the `searchExtended` condition to toggle between case-sensitive and insensitive searches.

```javascript
agent.customizeCollection('people', collection =>
  collection.replaceSearch((searchString, extendedMode) => {
    const operator = extendedMode ? 'Contains' : 'IContains';

    return {
      aggregator: 'Or',
      conditions: [
        { field: 'firstName', operator, value: searchString },
        { field: 'lastName', operator, value: searchString },
      ],
    };
  });
);
```

#### Changing searched columns

```javascript
const productReferenceRegexp = /^[a-f]{16}$/i;
const barCodeRegexp = /^[0-9]{10}$/i;

agent.customizeCollection('products', collection =>
  collection.replaceSearch(async (searchString, extendedMode, context) => {
    // User is searching using a product reference.
    if (productReferenceRegexp.test(searchString))
      return { field: 'reference', operator: 'Equal', value: searchString };

    // User is search a bar-code
    if (barCode.test(searchString))
      return { field: 'barCode', operator: 'Equal', value: Number(searchString) };

    // User is searching something else, in "normal mode", let's only search in the product name
    if (!extendedMode) return { field: 'name', operator: 'Contains', value: searchString };

    // In extended mode, we search on name, description and brand name
    return {
      aggregator: 'Or',
      conditions: [
        { field: 'name', operator: 'Contains', value: searchString },
        { field: 'description', operator: 'Contains', value: searchString },
        { field: 'brand:name', operator: 'Equal', value: searchString },
      ],
    };
  });
);
```

#### Calling an external API

If your data is indexed using a SaaS, external store, or full-text index, you can call it in the search handler.

```javascript
const algoliasearch = require('algoliasearch');
const client = algoliasearch('undefined', 'undefined');
const index = client.initIndex('indexName');

agent.customizeCollection('products', collection =>
  collection.replaceSearch(async (searchString, extendedMode, context) => {
    const { hits } = index.search(searchString, {
      attributesToRetrieve: ['id'],
      hitsPerPage: 50,
    });

    return { field: 'id', operator: 'In', value: hits.map(h => h.id) };
  });
);
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forestadmin.com/developer-guide-agents-nodejs/~/revisions/RIg7Xt85Z2LyzUxn7V93/agent-customization/search.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
