📑 In This Module
🎯 Learning Objectives
- Create searches programmatically using N/search
- Add filters with various operators
- Define result columns
- Perform joins to related records
- Process search results efficiently
- Load and execute saved searches
1. Search Basics
The N/search module lets you query NetSuite data. A search has three main components:
- Type - Which record type to search
- Filters - Conditions to narrow results (WHERE clause)
- Columns - Fields to return (SELECT clause)
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
| Operator | Use For | Example |
|---|---|---|
is | Exact match | ['status', 'is', 'A'] |
isnot | Not equal | ['status', 'isnot', 'C'] |
contains | Text contains | ['email', 'contains', 'gmail'] |
startswith | Text starts with | ['phone', 'startswith', '555'] |
anyof | In list | ['category', 'anyof', [1, 2, 3]] |
noneof | Not in list | ['status', 'noneof', ['X', 'Y']] |
greaterthan | Numeric > | ['amount', 'greaterthan', 100] |
lessthan | Numeric < | ['quantity', 'lessthan', 10] |
isnotempty | Has value | ['email', 'isnotempty', ''] |
isempty | No 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 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);
Each search.create() uses 5 units. search.lookupFields() uses 1 unit. Use lookupFields() for simple single-record lookups.
🏋️ Practice Exercises
Create a search that finds all Customers with "@gmail.com" in their email. Return companyname, email, and phone.
Search for Sales Orders with total > $1000 AND status = Open. Sort by total descending.
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)