# Optimize your agent

Your new agent is up and running, congratulations!

Because of the internal changes, you might already have noticed a performance improvement when you migrated your agent. Let's see how you can optimize your agent even more.

## Computed fields

### Replace queries with the `dependencies` option

A common pattern in the old agent was to make queries in the `get` function of a computed field to fetch relations.

This is now natively supported with the `dependencies` option, and it is much faster.

If you ported your agent by using the simpler route, which is copying the old agent code to the new agent, you can probably replace a lot of your queries with the `dependencies` option.

{% tabs %}
{% tab title="Before" %}

```javascript
agent.customizeCollection('post', postCollection => {
  postCollection.addField('authorFullName', {
    columnType: 'String',
    dependencies: ['authorId'],
    getValues: posts =>
      posts.map(async post => {
        // Those async queries take a long time and are performed in parallel with the other queries
        const author = await models.authors.findOne({ where: { id: post.authorId } });
        return `${author.firstName} ${author.lastName}`;
      }),
  });
});
```

{% endtab %}

{% tab title="After" %}

```javascript
agent.customizeCollection('post', postCollection => {
  postCollection.addField('authorFullName', {
    columnType: 'String',
    // The agent will automatically fetch the author collection and join it with the post collection
    // by performing a INNER JOIN on the authorId field.
    // This is _much_ faster than performing a query for each post

    dependencies: ['author:firstName', 'author:lastName'],
    getValues: posts => posts.map(post => `${post.author.firstName} ${post.author.lastName}`),
  });
});
```

or (better)

```javascript
// Define the field on the author collection
agent.customizeCollection('author', authorCollection => {
  authorCollection.addField('fullName', {
    columnType: 'String',
    dependencies: ['firstName', 'lastName'],
    getValues: authors => authors.map(author => `${author.firstName} ${author.lastName}`),
  });
});

// And then import it on the post collection
agent.customizeCollection('post', postCollection => {
  postCollection.importField('authorFullName', { path: 'author:fullName' });
});
```

{% endtab %}
{% endtabs %}

### Move async calls outside of the hot loop

The new computed field syntax works in batch mode.

If you have computed fields that take a long time to compute, you may want to use this new syntax to optimize them.

{% tabs %}
{% tab title="Before" %}

```javascript
agent.customizeCollection('users', users => {
  users.addField('full_address', {
    columnType: 'String',
    dependencies: ['address_id'],
    getValues: users =>
      users.map(async user => {
        // Get the address for each user individually
        // This is very slow if you are displaying a lot of users in a table
        const address = await geoWebService.getAddress(customer.address_id);

        return [address.line_1, address.line_2, address.city, address.country].join('\n');
      }),
  });
});
```

{% endtab %}

{% tab title="After" %}

```javascript
agent.customizeCollection('users', users => {
  users.addField('full_address', {
    columnType: 'String',
    dependencies: ['address_id'],
    getValues: async users => {
      // Get all the addresses in a single request
      // This is much faster if you are displaying a lot of users in a table
      const addresses = await geoWebService.getAddresses(users.map(user => user.address_id));

      // Return the full address for each user
      return users.map(user => {
        const address = addresses.find(address => address.id === user.address_id);

        return [address.line_1, address.line_2, address.city, address.country].join('\n');
      });
    },
  });
});
```

{% endtab %}
{% endtabs %}

### Avoid duplicate queries

If you happen to have computed fields that are similar, or that depend on the same data, you can make fields that depend on other fields.

{% tabs %}
{% tab title="Before" %}

```javascript
agent.customizeCollection('users', users => {
  users.addField('firstName', {
    columnType: 'String',
    dependencies: ['id'],
    getValues: async users => {
      const userInfo = await authenticationWebService.getUserInfo(users.map(user => user.id));
      return users.map(user => userInfo.find(userInfo => userInfo.id === user.id).firstName);
    },
  });

  users.addField('lastName', {
    columnType: 'String',
    dependencies: ['id'],
    getValues: async users => {
      const userInfo = await authenticationWebService.getUserInfo(users.map(user => user.id));
      return users.map(user => userInfo.find(userInfo => userInfo.id === user.id).lastName);
    },
  });
});
```

{% endtab %}

{% tab title="After" %}
Install the [`@forestadmin/plugin-flattener`](/developer-guide-agents-nodejs/~/revisions/RIg7Xt85Z2LyzUxn7V93/agent-customization/plugins/provided-plugins/flattener.md) plugin.

```console
npm install @forestadmin/plugin-flattener
```

Fetch all the user info in a single request, and then flatten the result.

```javascript
const { flattenColumn } = require('@forestadmin/plugin-flattener');

agent.customizeCollection('users', users => {
  users.addField('userInfo', {
    columnType: { firstName: 'String', lastName: 'String' },
    dependencies: ['id'],
    getValues: async users => {
      const userInfo = await authenticationWebService.getUserInfo(users.map(user => user.id));
      return users.map(user => userInfo.find(userInfo => userInfo.id === user.id));
    },
  });

  users.use(flattenColumn, { columnName: 'userInfo' });
});
```

{% endtab %}
{% endtabs %}

## Search

The new agent introduced the capability to customize the search behavior of your agent depending on the search query.

This is a very powerful feature that allows you to make sure that your agent is fast.

Documentation about this feature is available [here](/developer-guide-agents-nodejs/~/revisions/RIg7Xt85Z2LyzUxn7V93/agent-customization/search.md#changing-searched-columns).


---

# 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/getting-started/migrating/post-migration/optimize.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.
