🔍 search.create() vs Saved Searches
N/search offers two approaches: create dynamic searches in code, or load existing saved searches from the UI.
| Approach | Pros | Cons |
|---|---|---|
| search.create() | Version controlled, dynamic filters | More code, can't preview in UI |
| search.load() | Testable in UI, non-dev can modify | External dependency, migration needed |
🔧 Creating a Search
const search = require('N/search');
const customerSearch = search.create({
type: search.Type.CUSTOMER,
filters: [
['isinactive', 'is', 'F'],
'AND',
['balance', 'greaterthan', 0]
],
columns: [
search.createColumn({ name: 'entityid' }),
search.createColumn({ name: 'companyname' }),
search.createColumn({ name: 'email' }),
search.createColumn({ name: 'balance', sort: search.Sort.DESC })
]
});
// Execute and iterate
customerSearch.run().each(result => {
const name = result.getValue({ name: 'companyname' });
const balance = result.getValue({ name: 'balance' });
log.audit('Customer', `${name}: $${balance}`);
return true; // Continue to next result
});
🎯 Filters
Filters use a three-part array: [fieldId, operator, value]
// Simple filter
['isinactive', 'is', 'F']
// Multiple filters with AND/OR
[
['isinactive', 'is', 'F'],
'AND',
['subsidiary', 'anyof', [1, 2, 3]],
'AND',
[
['email', 'isnotempty', ''],
'OR',
['phone', 'isnotempty', '']
]
]
Common Operators
| Operator | Use Case |
|---|---|
| is | Exact match |
| anyof | Match any in list |
| contains | Text contains |
| greaterthan / lessthan | Numeric comparison |
| within | Date ranges |
| isnotempty | Has a value |
📊 Columns
// Basic column
search.createColumn({ name: 'companyname' })
// With sorting
search.createColumn({ name: 'balance', sort: search.Sort.DESC })
// Join column (related record)
search.createColumn({ name: 'city', join: 'billingaddress' })
// Summary/aggregate
search.createColumn({ name: 'amount', summary: search.Summary.SUM })
🔗 Joins
Access fields from related records using the join parameter:
// Get customer's primary contact email
const customerSearch = search.create({
type: search.Type.CUSTOMER,
columns: [
search.createColumn({ name: 'companyname' }),
search.createColumn({ name: 'email', join: 'contact' })
]
});
⚠️ Finding Join Names
Use the Records Browser or existing saved searches to discover valid join names. Common joins: entity, customer, item, transaction, contact, billingaddress.
📖 Loading Saved Searches
// Load by internal ID
const savedSearch = search.load({ id: 'customsearch_active_customers' });
// Modify filters dynamically
savedSearch.filters.push(
search.createFilter({
name: 'datecreated',
operator: search.Operator.ONORAFTER,
values: ['1/1/2024']
})
);
// Execute
savedSearch.run().each(result => {
// Process results
return true;
});
🔄 Iterating Results
run().each() Pattern
// Return true to continue, false to stop
search.run().each(result => {
const id = result.id;
const value = result.getValue({ name: 'companyname' });
return true; // Process up to 4000 results
});
runPaged() for Large Results
const pagedData = customerSearch.runPaged({ pageSize: 1000 });
pagedData.pageRanges.forEach(pageRange => {
const page = pagedData.fetch({ index: pageRange.index });
page.data.forEach(result => {
// Process each result
});
});
📖 Finding This in the Docs
To look up N/search methods:
- Go to docs.oracle.com → SuiteScript 2.x Modules
- Click on N/search Module
- Review search.create(), search.load(), Filter, and Column objects
Key pages to bookmark:
- search.create(options) → type, filters, columns parameters
- search.load(options) → loading saved searches
- Search.run() / Search.runPaged() → executing searches
- search.createFilter() → filter operators (is, anyof, contains, within)
- search.createColumn() → join, summary, sort options
- Result.getValue() vs Result.getText() → internal ID vs display value
🎯 Key Takeaways
- search.create() builds dynamic searches; search.load() uses saved searches
- Filters use [field, operator, value] syntax with AND/OR logic
- Columns can include joins to related records and summary functions
- run().each() returns up to 4,000 results
- runPaged() handles unlimited results with pagination
- getValue() returns internal IDs; getText() returns display values