Map/Reduce scripts are one of those SuiteScript features that look amazing on paper and then immediately get misused in the wild. I’ve seen Map/Reduce scripts that do everything in map, ignore reduce entirely, or blow through governance because they treat it like a scheduled script with extra steps.
Let’s talk about a few real-world patterns that make Map/Reduce scripts easier to reason about, easier to debug, and much more reliable in production.
This isn’t a deep dive into “what is Map/Reduce” — this is about how to actually use it day-to-day without hating your past self.
First: Stop Treating Map/Reduce Like a Scheduled Script
If your Map/Reduce script looks like this:
function getInputData() {return search.create({...});}
function map(context) {// Load record// Modify record// Save record}
You’re not wrong, but you’re missing most of the benefits.
Map/Reduce shines when:
- You separate read logic from write logic
- You group work intentionally
- You let NetSuite handle retries and governance
If everything lives in map, you’re basically just getting automatic rescheduling — which is fine, but we can do better.
Pattern #1: map = Normalize, reduce = Mutate
The cleanest mental model I’ve found:
- getInputData: fetch identifiers
- map: normalize data into a predictable shape
- reduce: do the actual record updates
- summarize: report, don’t repair
Example: Updating Transactions by Customer
getInputData
Return a saved search that gives you just enough data to do the job.
function getInputData() {return search.create({type: 'transaction',filters: [['mainline', 'is', 'T']],columns: ['internalid', 'entity']});}
map
Group transactions by customer.
function map(context) {var result = JSON.parse(context.value);context.write({
key: result.values.entity.value,value: result.id});}
The key thing here: no record loading, no saving.
Just shaping data.
reduce
Now you do the expensive stuff once per customer, not once per transaction.
function reduce(context) {var customerId = context.key;var transactionIds = context.values;transactionIds.forEach(function (id) {
var rec = record.load({type: record.Type.SALES_ORDER,id: id});rec.setValue({
fieldId: 'custbody_processed',value: true});rec.save();
});}
This pattern alone can cut governance usage dramatically.
Pattern #2: Don’t Be Afraid to Use Reduce for Single Records
A common misconception is that reduce is only useful when grouping many values. That’s not true.
If you want:
- Better retry behavior
- Cleaner separation of concerns
- Easier error tracking
…it’s often better to push everything into reduce, even if there’s only one value per key.
Example:
map(context) {context.write({key: context.key,value: context.value});}
Why bother?
Because reduce failures are isolated.
If one record fails, the others still finish cleanly.
Pattern #3: Treat Summarize as a Report, Not a Fixer
I’ve seen summarize functions that try to:
- Reload failed records
- Fix partial data
- Rerun business logic
Don’t do this.
summarize is for:
- Logging totals
- Reporting errors
- Sending notifications
Good summarize example
function summarize(summary) {if (summary.inputSummary.error) {log.error('Input Error', summary.inputSummary.error);}summary.reduceSummary.errors.iterator().each(function (key, error) {log.error('Reduce error for key ' + key, error);return true;});}
If you need recovery logic, build another script, not a clever summarize hack.
Pattern #4: Always Log with Context
When Map/Reduce scripts fail, debugging can be painful unless you log intentionally.
Bad log
log.error('Error', e);
Better log:
log.error({title: 'Reduce failed for customer ' + customerId,details: e});
Remember:
- Logs are often read days or weeks later
- You won’t remember what “Error saving record” meant at the time
Future you will thank present you for the extra context.
Pattern #5: Saved Searches > Ad‑Hoc Record Loads
If your Map/Reduce script:
- Loads records just to read fields
- Pulls child data inside loops
- Re-runs the same searches per record
…it’s probably doing too much work.
Where possible:
- Push data selection into
getInputData - Use summary columns
- Let the search engine do the heavy lifting
As a rule of thumb:
Search early, load late.
Final Thoughts
Map/Reduce isn’t about “processing lots of records” — it’s about processing them well.
If you:
- Keep
maplightweight - Use
reduceintentionally - Log like a responsible adult
- Let searches do the work
…your scripts will scale better, fail less often, and be much easier to maintain.
And the next developer to touch your code (which might be you in six months) won’t silently curse your name.
Comments
Post a Comment