safety-net

.map() your NetSuite Search Results

#array #javascript #suitescript

Almost every script that I write for NetSuite performs a search for some kind of data. You can accomplish this easily with SuiteScript by using either nlapiLoadSearch(), which will run an existing saved search and return the results, or nlapiSearchRecord(), which is used to build your saved search in code.

I prefer the latter option since the script does not have the external dependency on the saved search. If anyone were to change or delete that search, the script may no longer perform as expected. Also, by defining the search within the script itself the search logic can be stored in your source code repository.

Both of these functions return an array of nlobjSearchResult. but these objects can be cumbersome to work with and frequently calling getValue() or getText() can introduce a bit of noise into your code making it more difficult to read. I prefer to take these results and convert them into an an array of standard Javascript objects. This can make your search results easier to work with. Fortunately, the Javascript map() function works perfectly for this scenario. The map() function executes a callback function for each element in an array and creates a new array from the results of the callback function.

Consider the following example in which we want to search for all customers that have an open balance:

function getCustomersWithBalance() {
    var results = nlapiSearchRecord('customer', null, [
            new nlobjSearchFilter('balance', null, 'greaterthan', 0)
    ], [
            new nlobjSearchColumn('internalid'),
            new nlobjSearchColumn('entityid'),
            new nlobjSearchColumn('balance'),
            new nlobjSearchColumn('daysoverdue')
    ]);

    return results;
}

When working with the nlobjSearchResults returned by this function we need to call getValue() or getText() each time we need a piece of data.

var customers = getCustomersWithBalance();

var runningTotal = 0;
customers.forEach(function(customer) {
	runningTotal += customer.getValue(‘balance’);
	nlapiLogExecution(‘debug’, ‘balance’, customer.getValue(‘balance’));
});

In this example we are referencing the customer balance twice so getValue() is called each time. While this is certainly a very simple example, Imagine if our search returned 10 or 15 fields and we needed to use many of them several times. This is where the map() function shines. Let’s update our code to use it:

function getCustomersWithBalance() {
	var results = nlapiSearchRecord('customer', null, [
		new nlobjSearchFilter('balance', null, 'greaterthan', 0)
	], [
		new nlobjSearchColumn('internalid'),
		new nlobjSearchColumn('entityid'),
		new nlobjSearchColumn('balance'),
		new nlobjSearchColumn('daysoverdue')
	]);

	return (results || []).map(function(customer) {
		return {
			id: customer.getValue('internalid'),
			name: customer.getValue('entityid'),
			balance: customer.getValue('balance'),
			daysOvedue: customer.getValue('daysoverdue')
		};
	});
}

By using the map() function on our search results we can simplify our use of the data since we’re working with regular Javascript objects without the overhead of nlobjSearchResult:

var runningTotal = 0;
customers.forEach(function(customer) {
	runningTotal += customer.balance;
	nlapiLogExecution('debug', 'balance', customer.balance);
	nlapiLogExecution('debug', 'runningTotal', runningTotal);
});

Now each time we need to reference a customer’s balance, it’s simply customer.balance. Our code is cleaner and easier to read.

You may have noticed that I used the expression (results || []). Since the nlapiSearchRecord function returns null if there are no results, we would get an error trying to call map() on that null object. This expression is a shortcut way to say if the results are null, use and empty array instead. Our callback to the map() function is never called in this scenario, but an empty array is returned by our function. This ensures that our function always returns an array.

The map() function isn’t just for straight mapping from one object type to another, we can also use additional logic to add other properties to the returned objects. In this example, we’re going to add a flag to each customer object to determine if the customer is ‘high risk’ and indicate if the customer is a person or a company:

function getCustomersWithBalance() {
	var results = nlapiSearchRecord('customer', null, [
		new nlobjSearchFilter('balance', null, 'greaterthan', 0)
	], [
		new nlobjSearchColumn('internalid'),
		new nlobjSearchColumn('isperson'),
		new nlobjSearchColumn('entityid'),
		new nlobjSearchColumn('balance'),
		new nlobjSearchColumn('daysoverdue')
	]);

	return results.map(function(customer) {
		return {
			balance: customer.getValue('balance'),
			id: customer.getValue('internalid'),
			isHighRisk: customer.getValue('daysoverdue') > 60,
			isPerson: customer.getValue('isPerson') == 'T',
			name: customer.getValue('entityid')
		};
	});
}

var customers = getCustomersWithBalance();
customers.forEach(function(customer) {
	if (customer.isHighRisk && customer.isPerson) {
		nlapiLogExecution('debug', 'customer', customer.name);
		nlapiLogExecution('debug', 'balance', customer.balance);
	}
});

Now we have a nice function to retrieve a list of customers with an open balance made easy to use with the Javascript map() function.