Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The NetSuite Pro

The NetSuite Pro Logo The NetSuite Pro Logo

The NetSuite Pro Navigation

  • Home
  • About Us
  • Tutorials
    • NetSuite Scripting
    • Advanced PDF Templates in NetSuite
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask A Question
  • Home
  • About Us
  • Tutorials
    • NetSuite Scripting
    • Advanced PDF Templates in NetSuite
  • Blog
  • Contact Us
Home/ NetSuite Scripting/Using Saved Searches in Scripts (SuiteScript 2.1 Guide)

Using Saved Searches in Scripts (SuiteScript 2.1 Guide)

🔹 Introduction

Saved Searches let you pull data from NetSuite.

  • Admins build them in the UI.
  • Developers use them in SuiteScript to automate or process results.

This page shows how to:

  1. Load existing Saved Searches.
  2. Create ad-hoc searches directly in code.
  3. Use them in Map/Reduce scripts.
  4. Modify filters dynamically.

🔹 Example 1: Load an Existing Saved Search

/**
 *@NApiVersion 2.1
 *@NScriptType ScheduledScript
 */
define(['N/search'], (search) => {
    const execute = () => {
        try {
            // Load a saved search that was created in the NetSuite UI
            // Use its internal ID (you can find this in the search definition)
            const customerSearch = search.load({
                id: 'customsearch_my_customer_search' // <-- replace with your saved search ID
            });

            // Run the search and iterate through results
            // .each() lets you go row by row
            customerSearch.run().each(result => {
                // Get the values for each column
                const name = result.getValue('entityid');  // Customer name/ID
                const email = result.getValue('email');    // Customer email address
                
                // Log output for debugging
                log.debug('Customer', `${name} | ${email}`);
                
                return true; // MUST return true to continue iteration
            });
        } catch (e) {
            log.error('Error loading saved search', e.message);
        }
    };
    return { execute };
});

💡 Explanation:

  • Use this when admins maintain search logic in the UI.
  • Developers simply reference the search by ID.

🔹 Example 2: Create an Ad-Hoc Search

/**
 *@NApiVersion 2.1
 *@NScriptType ScheduledScript
 */
define(['N/search'], (search) => {
    const execute = () => {
        try {
            // Create a search fully in code (no UI search needed)
            const customerSearch = search.create({
                type: search.Type.CUSTOMER,                // Search on Customer records
                filters: [['isinactive', 'is', 'F']],      // Only active customers
                columns: ['entityid', 'email']             // Return Customer Name + Email
            });

            // Run the search and fetch first 5 results only
            const results = customerSearch.run().getRange({ start: 0, end: 5 });

            // Loop through results and log
            results.forEach(result => {
                const name = result.getValue('entityid');
                const email = result.getValue('email');
                log.debug('Customer', `${name} | ${email}`);
            });
        } catch (e) {
            log.error('Error in ad-hoc search', e.message);
        }
    };
    return { execute };
});

💡 Explanation:

  • This method gives full control in code.
  • Use .getRange() for small batches (use Map/Reduce for large sets).

🔹 Example 3: Saved Search in Map/Reduce

/**
 *@NApiVersion 2.1
 *@NScriptType MapReduceScript
 */
define(['N/search'], (search) => {
    // getInputData defines where the Map/Reduce pulls input from
    const getInputData = () => {
        try {
            // Load a saved search of open Sales Orders
            return search.load({
                id: 'customsearch_open_salesorders' // Replace with your saved search ID
            });
        } catch (e) {
            log.error('Error in getInputData', e.message);
        }
    };

    // map runs once per search result
    const map = (context) => {
        try {
            // context.value is a JSON string of the result
            const result = JSON.parse(context.value);

            log.debug('Map Stage', `SO ID: ${result.id}, Customer: ${result.values.entity}`);

            // Write forward key/value pairs to reduce stage
            context.write({
                key: result.values.entity.value,   // Customer ID
                value: result.id                   // Sales Order ID
            });
        } catch (e) {
            log.error('Error in map', e.message);
        }
    };

    // reduce consolidates data for each key
    const reduce = (context) => {
        try {
            log.debug('Reduce Stage', `Customer: ${context.key}, Orders: ${context.values.length}`);
        } catch (e) {
            log.error('Error in reduce', e.message);
        }
    };

    // summarize runs once after everything
    const summarize = (summary) => {
        try {
            log.debug('Summary', `Usage Consumed: ${summary.usage}`);
        } catch (e) {
            log.error('Error in summarize', e.message);
        }
    };

    return { getInputData, map, reduce, summarize };
});

💡 Explanation:

  • Perfect for large data jobs.
  • Admins build the Saved Search, developers process it via Map/Reduce.

🔹 Example 4: Modify Saved Search Filters Dynamically

/**
 *@NApiVersion 2.1
 *@NScriptType ScheduledScript
 */
define(['N/search'], (search) => {
    const execute = () => {
        try {
            // Load base Sales Order search from the UI
            const soSearch = search.load({
                id: 'customsearch_open_salesorders'
            });

            // Add extra filter at runtime: Only Sales Orders for Customer ID = 123
            soSearch.filters.push(['entity', 'anyof', '123']); 

            // Get first 3 results
            const results = soSearch.run().getRange({ start: 0, end: 3 });

            results.forEach(result => {
                const soId = result.id;
                const customerName = result.getText('entity');
                log.debug('Filtered SO', `SO ID: ${soId} | Customer: ${customerName}`);
            });
        } catch (e) {
            log.error('Error modifying saved search', e.message);
        }
    };
    return { execute };
});

💡 Explanation:

  • Useful if you want a base Saved Search but add filters dynamically (e.g., by customer, subsidiary, or date).

🔹 Best Practices

  • Use search.load() when admins maintain criteria in the UI.
  • Use search.create() for dev-only automation.
  • Use .each() for streaming large result sets (but be mindful of governance).
  • Use .getRange() for smaller chunks of data.
  • In Map/Reduce, always pass Saved Searches in getInputData.
  • Wrap everything in try–catch and log errors for debugging.

✅ Key Takeaway

Saved Searches are the bridge between admins and developers. Admins build the logic in the UI, and developers use that logic in SuiteScript for automation, reporting, and large-scale data jobs.

Share
  • Facebook

Sidebar

Ask A Question

Stats

  • Questions 6
  • Answers 6
  • Best Answers 0
  • Users 2
  • Popular
  • Answers
  • Rocky

    Issue in running a client script in NetSuite SuiteScript 2.0 ...

    • 1 Answer
  • admin

    How can I send an email with an attachment in ...

    • 1 Answer
  • admin

    How do I avoid SSS_USAGE_LIMIT_EXCEEDED in a Map/Reduce script?

    • 1 Answer
  • admin
    admin added an answer The issue is usually caused by following Wrong script file… September 14, 2025 at 10:33 pm
  • admin
    admin added an answer Steps to send an Invoice PDF by email: define(['N/email', 'N/render',… August 28, 2025 at 3:05 am
  • admin
    admin added an answer This error means your script hit NetSuite’s governance usage limit… August 28, 2025 at 3:02 am

Top Members

Rocky

Rocky

  • 1 Question
  • 21 Points
Begginer
admin

admin

  • 5 Questions
  • 2 Points

Trending Tags

clientscript netsuite scripting suitescript

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help

Footer

© 2025 The NetSuite Pro. All Rights Reserved