# Search

Searchable fulfillmenttools entities have a dedicated search endpoint located at `POST /api/{ENTITY-NAME}/search`. Each fulfillmenttools entity defines which of its fields are queryable. You can:

* Search string and number fields with the operators `eq`, `notEq`, `in`, and `notIn`. The search value for `eq` and `notEq` must be a string, while the value for `in` and `notIn` must be an array of strings.
* Search array-of-string fields with the `contains` operator.
* Search number and date fields with the operators `gt` (>), `gte` (>=), `lt` (<), and `lte` (<=).
* Search all `customAttributes`. However, to optimize performance, it's recommended to store search-relevant keys in a dedicated property (for example, `searchTerms`) and minimize nesting depth.

## Fields with default query limits

Some entities, particularly those representing historical data, include default filters in queries. These default search fields limit the amount of data returned, which improves performance and relevance.

For example, operational entities such as orders typically return only recently created records by default, as older data is often not relevant for current operations.

These default values can be overridden if needed. However, expanding filters requires caution, especially when querying large datasets, to avoid performance issues.

## Search function limitations

The search functionality has the following restrictions due to database constraints and performance considerations. These limitations ensure stability and efficiency when handling queries.

1. **No periods (`.`) in custom search field names:** Field names containing periods can cause conflicts with internal database structures and indexing mechanisms. To prevent issues, periods aren't allowed in custom search field names.
2. **No custom search fields starting with a dollar sign (`$`):** Field names beginning with a dollar sign conflict with database operators, which use this syntax for system commands. To avoid ambiguity, such field names aren't permitted.
3. **Cross-entity search via `referenced` filter is limited to top-level queries:** Cross-entity searches using the `referenced` filter can only be applied at the top level of a query. Nesting them within `AND` or `OR` conditions is not supported due to query optimization constraints.

## Search execution time limit

Each search request must complete within a 30-second time limit. If execution exceeds this limit, the system aborts the search and returns a `BadRequest` response. Long runtimes can result from a combination of query complexity and the volume of entities searched. When encountering timeouts, reduce the complexity (for example, simplify nested conditions, narrow filters, avoid overly broad `customAttribute` queries), narrow the size of the dataset (for example, by providing a time range or restricting the search to a specific facility), or contact the support team for guidance.

## Example API calls

### Searching for exact equal matches

Example: Search for stocks in a facility with `facilityRef` `d083f631-9f4c-463b-85d4-9414fb19239f`.

```http
POST https://{projectId}.api.fulfillmenttools.com/api/stocks/search
```

```json
{
    "query": {
        "facilityRef": {
            "eq": "d083f631-9f4c-463b-85d4-9414fb19239f"
        }
    }
}
```

### Searching with `gt`, `gte`, `lt`, and `lte` operators

Example: Search for storage locations with a `created` date before October 2, 2024.

```http
POST https://{projectId}.api.fulfillmenttools.com/api/storagelocations/search
```

```json
{
    "query": {
        "created": {
            "lt": "2024-10-02T14:43:21.257Z"
        }
    }
}
```

### Sorting search results

```http
POST https://{projectId}.api.fulfillmenttools.com/api/{ENTITY-NAME}/search
```

```json
{
    "sort": [
        {
            "<attribute_to_sort_by>": "ASC"
        }
    ],
    "query": {
      ...
    }
}
```

### Adding a search result total count

{% hint style="warning" %}
Requesting the total count can significantly increase the response time of the request.
{% endhint %}

```http
POST https://{projectId}.api.fulfillmenttools.com/api/{ENTITY-NAME}/search
```

```json
{
    "options": {
        "withTotal": true
    },
    "query": {
      ...
    }
}
```

{% hint style="info" %}
The `withTotal` option cannot be used in combination with `after` for pagination. This restriction exists because the total count may change while paginating, which could lead to inconsistent results.
{% endhint %}

### Searching for several fields with `and` or `or`

Example: Search for stocks that have a `facilityRef` of `d083f631-9f4c-463b-85d4-9414fb19239f` and are also placed on either location `6779689d-4852-4fcf-b13b-78f5ce4954d8` or `3b8be595-6a00-40cf-be09-12195e44eb99`.

```http
POST https://{projectId}.api.fulfillmenttools.com/api/stocks/search
```

```json
{
    "query": {
        "and": [
            {
                "facilityRef": {
                    "eq": "d083f631-9f4c-463b-85d4-9414fb19239f"
                }
            }, {
                "locationRef": {
                    "in": [
                        "6779689d-4852-4fcf-b13b-78f5ce4954d8",
                        "3b8be595-6a00-40cf-be09-12195e44eb99"
                    ]
                }
            }
        ]
    }
}
```

### Searching for nested fields

Example: Search for `inboundProcesses` that reference a `purchaseOrder` with the `id` `678ujnuzb67vg8h8oji`.

```http
POST https://{projectId}.api.fulfillmenttools.com/api/inboundprocesses/search
```

```json
{
    "query": {
        "purchaseOrder": {
            "id": {
                "eq": "678ujnuzb67vg8h8oji"
            }
        }
    }
}
```

### Searching for custom attributes

Users can make fields in `customAttributes` searchable by defining key-value pairs within the `searchTerms` property. All defined key-value pairs are then queryable in the search endpoints. The `customAttributes` can contain strings and numbers. For strings, the `in` and `notIn` operators are allowed. For numbers, the `lt`, `lte`, `gt`, and `gte` operators are also available.

{% hint style="warning" %}
When searching a number attribute, use a number value in the query. Similarly, use a string value for a string attribute. Otherwise, the search will not return the expected results. For example, a search for the number `5` using `eq: "5"` will not be successful.
{% endhint %}

Example: Create a new storage location with user-defined, searchable custom attributes and then execute a search for them.

1. Create a new entity with user-defined custom attributes that should be searchable via `searchTerms`.

```http
POST https://{projectId}.api.fulfillmenttools.com/api/{facilityId}/storagelocations
```

```json
...
"customAttributes": {
  "searchTerms": {
    "TYPE": "FROZEN"
  }
}
...
```

2. Construct a search query on the custom attributes.

```http
POST https://{projectId}.api.fulfillmenttools.com/api/storagelocations/search
```

```json
{
  "query": {
    "customAttributes": {
      "searchTerms": {
        "TYPE": {
          "eq": "FROZEN"
        }
      }
    }
  }
}
```
