Module 7: Searching in NetSuite

Week 4 • NetSuite SuiteScript 2.0 Training • ~90 minutes

🎯 Learning Objectives

1. Search Basics

The N/search module lets you query NetSuite data. A search has three main components:

define(['N/search'], function(search) {
    
    var customerSearch = search.create({
        type: search.Type.CUSTOMER,
        filters: [
            ['email', 'isnotempty', '']
        ],
        columns: [
            'entityid',
            'companyname',
            'email'
        ]
    });
    
});

2. Search Filters

Filters narrow your search results. Each filter has three parts:

// Format: [fieldId, operator, value]
['email', 'contains', '@gmail.com']
['total', 'greaterthan', 1000]
['status', 'anyof', ['A', 'B']]

Common Operators

OperatorUse ForExample
isExact match['status', 'is', 'A']
isnotNot equal['status', 'isnot', 'C']
containsText contains['email', 'contains', 'gmail']
startswithText starts with['phone', 'startswith', '555']
anyofIn list['category', 'anyof', [1, 2, 3]]
noneofNot in list['status', 'noneof', ['X', 'Y']]
greaterthanNumeric >['amount', 'greaterthan', 100]
lessthanNumeric <['quantity', 'lessthan', 10]
isnotemptyHas value['email', 'isnotempty', '']
isemptyNo value['fax', 'isempty', '']

Combining Filters (AND/OR)

// AND - all conditions must match (default)
filters: [
    ['total', 'greaterthan', 1000],
    'AND',
    ['status', 'is', 'Open']
]

// OR - any condition matches
filters: [
    ['email', 'contains', '@gmail.com'],
    'OR',
    ['email', 'contains', '@yahoo.com']
]

// Complex: (A AND B) OR (C AND D)
filters: [
    [['status', 'is', 'Open'], 'AND', ['total', 'greaterthan', 1000]],
    'OR',
    [['status', 'is', 'Pending'], 'AND', ['priority', 'is', 'High']]
]

3. Search Columns

Columns define what data to return:

// Simple - just field names
columns: ['entityid', 'email', 'phone']

// With options
columns: [
    search.createColumn({ name: 'entityid' }),
    search.createColumn({ name: 'total', sort: search.Sort.DESC }),
    search.createColumn({ name: 'trandate', label: 'Order Date' })
]

4. Joins

Joins let you access fields from related records. Use the join parameter:

// Search Sales Orders, get Customer email
var orderSearch = search.create({
    type: search.Type.SALES_ORDER,
    columns: [
        'tranid',
        'total',
        search.createColumn({
            name: 'email',
            join: 'customer'  // Join to customer record
        }),
        search.createColumn({
            name: 'companyname',
            join: 'customer'
        })
    ]
});
💡 Join Names

Join names are usually the field ID that links to the other record. On a Sales Order, customer is the field linking to the Customer record. Check the Records Browser for valid join names.

5. Running Searches

Method 1: run().each() - Most Common

customerSearch.run().each(function(result) {
    var name = result.getValue('companyname');
    var email = result.getValue('email');
    log.debug('Customer', name + ': ' + email);
    
    return true; // Continue to next result (false stops)
});
// Note: Automatically handles up to 4000 results

Method 2: getRange() - For Pagination

var results = customerSearch.run().getRange({
    start: 0,
    end: 100  // Get first 100 results
});

for (var i = 0; i < results.length; i++) {
    log.debug('Result ' + i, results[i].getValue('companyname'));
}

Method 3: runPaged() - Large Result Sets

var pagedData = customerSearch.runPaged({ pageSize: 1000 });

pagedData.pageRanges.forEach(function(pageRange) {
    var page = pagedData.fetch({ index: pageRange.index });
    
    page.data.forEach(function(result) {
        log.debug('Customer', result.getValue('companyname'));
    });
});

Getting Values vs Text

result.getValue('salesrep');  // Returns: 42 (internal ID)
result.getText('salesrep');   // Returns: "John Smith" (display text)

6. Loading Saved Searches

You can run searches created in the UI:

// Load by internal ID
var savedSearch = search.load({ id: 'customsearch_open_orders' });

// Optionally modify filters
savedSearch.filters.push(
    search.createFilter({
        name: 'total',
        operator: search.Operator.GREATERTHAN,
        values: 5000
    })
);

// Run it
savedSearch.run().each(function(result) {
    // Process results
    return true;
});

Quick Lookup

For simple lookups, use search.lookupFields():

var customerData = search.lookupFields({
    type: search.Type.CUSTOMER,
    id: 123,
    columns: ['companyname', 'email', 'phone']
});

log.debug('Name', customerData.companyname);
log.debug('Email', customerData.email);
⚠️ Governance

Each search.create() uses 5 units. search.lookupFields() uses 1 unit. Use lookupFields() for simple single-record lookups.

🏋️ Practice Exercises

Exercise 1: Basic Search

Create a search that finds all Customers with "@gmail.com" in their email. Return companyname, email, and phone.

Exercise 2: Filtered Search

Search for Sales Orders with total > $1000 AND status = Open. Sort by total descending.

Exercise 3: Join Search

Search Support Cases and include the assigned employee's department and job title using joins.

🎯 Key Takeaways

  • Searches have type, filters, and columns
  • Filters format: [fieldId, operator, value]
  • Use 'AND' and 'OR' between filters for complex logic
  • Joins access related record fields
  • run().each() is the most common way to process results
  • Use lookupFields() for simple single-record lookups (lower governance)