Search
This is the official documentation of Forest Admin Cloud.
To improve your admin panel's search functionality, consider overriding the default search system with more efficient technologies. Options like PostgreSQL's tsquery
and tsvector
, Algolia, or Elasticsearch provide advanced search capabilities and faster query responses. These tools can significantly improve your app's search results and performance.
To make the code easier to read, all the code snippets below should be wrapped in the following code. Ensure you update the collection name as needed.
import type { Agent } from '@forestadmin/forest-cloud';
import { Schema } from '../typings';
export default function customizeAgent(agent: Agent<Schema>) {
agent.customizeCollection('users', collection =>
// Insert the code snippet here.
);
}
Extending the default search engine
To modify your collection's default search behavior, use the replaceSearch()
function. This function provides access to the default search logic through the context
argument.
collection.replaceSearch((searchString, extendedMode, context) => {
return context.generateSearchFilter(searchString, {
extended: extendedMode;
excludeFields: ['gender'];
includeFields: ['address:street'];
})
});
Arguments:
excludedFields
* [String]: Remove the fields to the default search engine.extended
* Boolean: When activated, extended search also includes direct relationships.includeFields
* [String]: Add the fields to the default search engine.
The generateSearchFilter()
function returns an object containing the set of rules for searching. You can adjust these rules to better fit your needs or to make your searches more efficient.
collection.replaceSearch((searchString, extendedMode, context) => {
const defaultCondition = context.generateSearchFilter(searchString, {
extended: extendedMode;
excludeFields: ['gender'];
includeFields: ['address:street'];
});
return {
aggregator: 'Or',
conditions: [
defaultCondition,
{ field: 'address:street', operator: 'IContains', value: searchString },
]
};
});
Examples
Enabling case-sensitivity
By default, searches are case insensitive. To enable case-sensitive searches, switch from the IContains
operator to the Contains
operator.
collection.replaceSearch((searchString, extendedMode, context) => {
const defaultCondition = context.generateSearchFilter(searchString);
return {
aggregator: 'Or',
conditions: [
defaultCondition,
{ field: 'first_name', operator: 'Contains', value: searchString },
{ field: 'last_name', operator: 'Contains', value: searchString },
]
};
});
Searching on specific columns based on user input format
To improve the default search functionality, this example below differentiates between a product reference (e.g., bcdaefCFABDEdfEF
) and a barcode value (e.g., 9876543210
) using regex. This enables the search to target the appropriate field based on the input type.
const productReferenceRegexp = /^[a-f]{16}$/i;
const barCodeRegexp = /^[0-9]{10}$/i;
collection.replaceSearch(async (searchString, extendedMode, context) => {
if (productReferenceRegexp.test(searchString)) {
return context.generateSearchFilter(searchString, {
onlyFields: ['reference'],
});
} else if (barCode.test(searchString)) {
return context.generateSearchFilter(searchString, {
onlyFields: ['barCode'],
});
} else {
return context.generateSearchFilter(searchString);
}
});
Using an external API
When your data is stored and organized in a cloud-based service, another storage system, or a service specifically for searching through text, you can opt to use these instead of the default search engine.
const algoliasearch = require('algoliasearch');
const client = algoliasearch('APPLICATION_ID', 'WRITE_API_KEY');
const index = client.initIndex('indexName');
collection.replaceSearch(async (searchString, extendedMode, context) => {
const { hits } = await index.search(searchString, {
attributesToRetrieve: ['id'],
hitsPerPage: 50,
});
return { field: 'id', operator: 'In', value: hits.map(h => h.id) };
});
Last updated
Was this helpful?