Optimizing Saved Search Execution in NetSuite by Passing an Array of Filters

NetSuite scripts often require retrieving data for multiple items or records, especially when processing transactions with several lines. A common, but inefficient, approach is to run a saved search for each line, which can lead to performance issues and script governance limit violations. A better solution is to pass an array of filters to a single saved search, enabling batch processing and improving efficiency.

Why Avoid Running a Saved Search for Each Line?

  1. Governance Limits: Saved searches consume NetSuite governance units, and running a search for each line can quickly exhaust the available limits.
  2. Performance Impact: Executing multiple saved searches increases processing time, slowing down the script and potentially causing timeouts.
  3. Complexity: Managing individual saved search calls for each line adds unnecessary complexity to the code.

Using Filter Arrays to Optimize Saved Searches

By passing an array of filters, you can retrieve data for multiple records in a single saved search. This approach reduces governance consumption, simplifies code, and enhances script performance.

Key Benefits

  1. Efficiency: A single execution retrieves all required data at once.
  2. Governance Savings: Fewer saved search executions mean fewer governance units consumed.
  3. Scalability: This approach handles large datasets more effectively.

Implementing Filter Arrays in a Script

Step 1: Create a Saved Search

Create a saved search with criteria that can accept dynamic filters. For example, if you’re searching for items, ensure the search can filter based on multiple item IDs.

Step 2: Pass Filters Dynamically

In your script, prepare an array of filters based on the data you need to retrieve. Use the search.create method to run the search with these filters.

Example Script

Here’s a sample script that retrieves data for multiple item lines using a single saved search:

/**
 * @NApiVersion 2.x
 * @NScriptType UserEventScript
 */
define(['N/search', 'N/log'], function(search, log) {
    function beforeSubmit(context) {
        var newRecord = context.newRecord;
        var itemCount = newRecord.getLineCount({ sublistId: 'item' });
        var itemIds = [];

        // Collect all item IDs from the transaction lines
        for (var i = 0; i < itemCount; i++) {
            var itemId = newRecord.getSublistValue({
                sublistId: 'item',
                fieldId: 'item',
                line: i
            });

            if (itemId) {
                itemIds.push(itemId);
            }
        }

        if (itemIds.length > 0) {
            // Create a filter array for the saved search
            var filters = [
                search.createFilter({
                    name: 'internalid',
                    operator: search.Operator.ANYOF,
                    values: itemIds
                })
            ];

            // Execute the saved search with the filter array
            var itemSearch = search.create({
                type: search.Type.ITEM,
                filters: filters,
                columns: [
                    'internalid',
                    'displayname',
                    'custitem_custom_field' // Example field
                ]
            });

            var results = [];
            itemSearch.run().each(function(result) {
                results.push({
                    id: result.getValue('internalid'),
                    name: result.getValue('displayname'),
                    customField: result.getValue('custitem_custom_field')
                });
                return true;
            });

            log.debug('Search Results', results);

            // Process results (e.g., update lines or store data)
            // Example: Set a custom field on each line
            results.forEach(function(item) {
                for (var i = 0; i < itemCount; i++) {
                    var lineItemId = newRecord.getSublistValue({
                        sublistId: 'item',
                        fieldId: 'item',
                        line: i
                    });

                    if (lineItemId == item.id) {
                        newRecord.setSublistValue({
                            sublistId: 'item',
                            fieldId: 'custcol_custom_field', // Example custom column
                            line: i,
                            value: item.customField
                        });
                    }
                }
            });
        }
    }

    return {
        beforeSubmit: beforeSubmit
    };
});

Key Steps Explained

  1. Extract Line Data: Gather all unique IDs from the transaction lines.
  2. Create Filter Array: Use the gathered IDs to create a filter array.
  3. Execute a Single Search: Pass the filter array to the saved search and retrieve all required data in one execution.
  4. Process Results: Use the search results to update or validate data on each transaction line.

Tips for Effective Implementation

  1. Optimize Filters: Ensure your filters are precise to avoid retrieving unnecessary data.
  2. Batch Processing: For very large datasets, split the IDs into manageable batches to avoid hitting result limits.
  3. Reuse Saved Searches: Use a single reusable saved search template with dynamic filters to simplify maintenance.
  4. Handle Errors: Implement error handling for cases where data might be missing or the search fails.

Conclusion

Passing an array of filters to a saved search is a best practice for handling large datasets in NetSuite scripts. This approach eliminates the inefficiencies of running individual searches for each line, saving governance units and improving overall performance. By leveraging filter arrays and a single saved search, your scripts will be more efficient, maintainable, and scalable.

Leave a comment

Your email address will not be published. Required fields are marked *