Expand your SuiteScript skills in the Sustainable SuiteScript community for NetSuite developers.

3 Working with Records in SuiteScript 2.0

Created: May 15, 2017

Maybe the most fundamental concept to master in SuiteScript is working with NetSuite's Record objects. Records are our interface to the NetSuite database. If we're unable to work with records, we are pretty useless as NetSuite developers, so in this article we will investigate how we modify record objects in SuiteScript 2.0 as compared to 1.0. The core of this functionality in SuiteScript 2.0 is provided by the N/record module.

N/record

The record module allows us to manipulate record objects within the NetSuite database. It encapsulates a large number of record manipulation functions and objects from SuiteScript 1.0:

  • nlapiLoadRecord
  • nlapiCreateRecord
  • nlapiSubmitRecord
  • nlapiCopyRecord
  • nlapiTransformRecord
  • nlapiDeleteRecord
  • nlapiAttachRecord
  • Inline editing via nlapiSubmitRecord
  • nlobjRecord

We won't cover all of these operations explicitly in this article, but we'll show the fundamentals for manipulating records and body fields. Working with sublists, subrecords, and many of these other operations will all be covered in later articles.

API Equivalencies

Before we jump in to some code, let's take a look at a little more detail of the methods we're going to cover today and how they've been translated from 1.0 to 2.0.

We are assuming the N/record module has been imported into our module as r, like so:

define(["N/record"], function (r) { ... });

Equivalencies between the SuiteScript 1.0 and 2.0 APIs for working with Record objects

The first thing to notice here is that there is essentially a 1:1 equivalency in these 1.0 functions and their 2.0 counterparts. The nlobjRecord Object type has also been translated to the Record Object type within the N/record module, and it contains similar get and set methods to its 1.0 counterpart. If you're already well familiar with these 1.0 functions, working with records should be a straight-forward transition for you to make.

You'll also notice that all of the 2.0 functions accept a single Object parameter, which is typically named options in the Help documentation. This should not be a surprise if you read ESS #2: SuiteScript 2.0 Modules, where we stated that all 2.0 functions follow this pattern of accepting a single Object argument rather than a list of separate arguments as they do in 1.0.

Lastly, you can see that load, create, and delete are methods on the module itself. load and create both return instances of r.Record, and the save method lives on the Record instance rather than on the module as you might have expected.

Creating Records

After that wall of information, it's time to look at an actual example. What we're going to do is create a User Event script that runs on the afterSubmit event and creates a new Contact record. We will create a version of this in both SuiteScript 1.0 and 2.0 and show them side-by-side.

The important focus here is to see the equivalent code between the two versions, so I won't be showing how to deploy and test these scripts. Any testing is left to you as an exercise.

Let's create a very simple Contact record with a name, email, and phone number.

// 1.0
function afterSubmit(type) {
	var contact = nlapiCreateRecord("contact", null);
	contact.setFieldValue("firstname", "Eric");
	contact.setFieldValue("middlename", "T");
	contact.setFieldValue("lastname", "Grubaugh");
	contact.setFieldValue("email", "eric@stoic.software");
	contact.setFieldValue("officephone", "+16233491564");
	nlapiSubmitRecord(contact);
}
// 2.0 - Fluent
/**
 * @NApiVersion 2.0
 * @NScriptType UserEventScript
 * @NModuleScope SameAccount
 */
define(["N/record"], function (r) {
    function createContact() {
        r.create({type: r.Type.CONTACT, isDynamic: false, defaultValues: null}).setValue({
            fieldId: "firstname",
            value: "Eric",
            ignoreFieldChange: true
        }).setValue({fieldId: "middlename", value: "T"}).setValue({
            fieldId: "lastname",
            value: "Grubaugh"
        }).setValue({fieldId: "email", value: "eric@stoic.software"}).setValue({
            fieldId: "officephone",
            value: "+16233491564"
        }).save({enableSourcing: true, ignoreMandatoryFields: false});
    }

    return {afterSubmit: createContact};
});

Personally, I prefer the fluent method chaining shown here, but it is not mandatory. If you prefer, you can avoid method chaining by storing a reference to the newly created Record instance in a variable, like so:

// 2.0 - No chaining
/**
 * @NApiVersion 2.0
 * @NScriptType UserEventScript
 * @NModuleScope SameAccount
 */
define(["N/record"], function (r) {
    function createContact() {
        var contact = r.create({
            type: r.Type.CONTACT,
            isDynamic: false,
            defaultValues: null
        });

        contact.setValue({
            fieldId: "firstname",
            value: "Eric",
            ignoreFieldChange: false
        });
        contact.setValue({
            fieldId: "middlename",
            value: "T"
        });
        contact.setValue({
            fieldId: "lastname",
            value: "Grubaugh"
        });
        contact.setValue({
            fieldId: "email",
            value: "eric@stoic.software"
        });
        contact.setValue({
            fieldId: "officephone",
            value: "+16233491564"
        });

        contact.save({
            enableSourcing: true,
            ignoreMandatoryFields: false
        });
    }

    return {
        afterSubmit: createContact
    };
});

Admittedly, this is not a practical example at all; you certainly wouldn't want to repeatedly create the same Contact over and over on every afterSubmit event. However, if I tried to throw in too much logic, it would just muddy the example and obscure the focus of the article, which is the transition from 1.0 to 2.0.

We've just seen how to create a new record by writing to body fields, but what about reading field values? As you might imagine, just like the nlobjRecord from SuiteScript 1.0 has a setFieldValue and a getFieldValue, the 2.0 Record instance has setValue and getValue.

Loading Records and Reading Body Fields

Let's look at a similar User Event script that might be deployed on a Customer record to read data from the associated Sales Rep record.

We'll grab a reference to the current record via nlapiGetNewRecord. If there's a Sales Rep specified, we'll load the Employee record for the Sales Rep, and we'll retrieve the email address for the Sales Rep. Then we'll hand that email address of to an incredible function that sends a tremendously valuable email to the Sales Rep. I leave the details of such a notification up to you.

// 1.0
function afterSubmit(type) {
    var currentRecord = nlapiGetNewRecord();
    var salesRepId = currentRecord.getFieldValue("salesrep");
    if (!salesRepId) {
        return;
    }
    var salesRepRec = nlapiLoadRecord("employee", salesRepId);
    var salesRepEmail = salesRepRec.getFieldValue("email");
    if (salesRepEmail) {
        sendAwesomeNotification(salesRepEmail);
    }
}

function sendAwesomeNotification(email) {
    // Send a super useful, actionable notification to the provided email address
}
// 2.0 - Fluent
/**
 * @NApiVersion 2.0
 * @NScriptType UserEventScript
 * @NModuleScope SameAccount
 * @appliedtorecord customer
 */
define(["N/record"], function (r) {
    function onAfterSubmit(context) {
        var currentRecord = context.newRecord;
        var salesRepId = currentRecord.getValue({fieldId: "salesrep"});
        if (!salesRepId) {
            return;
        }
        var salesRepRec = r.load({type: r.Type.EMPLOYEE, id: salesRepId, isDynamic: false, defaultValues: null});
        var salesRepEmail = salesRepRec.getValue({fieldId: "email"});
        if (salesRepEmail) {
            sendAwesomeNotification(salesRepEmail);
        }
    }

    function sendAwesomeNotification(email) {
        // Send a super useful, actionable notification to the provided email address
    }

    return {afterSubmit: onAfterSubmit};
});

Something we have not examined as yet is the context parameter that gets passed in to our User Event script by NetSuite. The details of this parameter will be covered in a later topic specifically covering User Events. For now, let it suffice to say that instead of the global functions nlapiGetNewRecord and nlapiGetOldRecord from SuiteScript 1.0, NetSuite now passes references to these into our event handler via the context parameter.

Again, I will leave actually deploying and testing such a script up to you.

Why no Lookup?

A quick note here: If your hair is currently on fire because I'm not using nlapiLookupField, I completely understand where you're coming from.

nlapiLookupField is a much faster way of retrieving body-level data from related records. SuiteScript 2.0 does have an equivalent lookup functionality, but it is located in the N/search module, and I didn't feel it appropriate to introduce a whole new module just yet. Rest assured, I will be covering lookups and the N/search module in detail later in the series. For now, I'll have to ask that you be patient with me.

At this point, we've seen how to create new records, load existing records, and read from and write to body fields. Our final example will be looking at how to delete records. This again is a very straight-forward transition to make if you're familiar with nlapiDeleteRecord in SuiteScript

Deleting Records

This time, we'll create a very simple Mass Update script that just deletes any record passed to it.

Quick disclaimer: Please be extremely careful if you actually try to test this example!

function each(recordType, recordId) {
    nlapiDeleteRecord(recordType, recordId);
}
/**
 * @NApiVersion 2.0
 * @NScriptType MassUpdateScript
 * @NModuleScope SameAccount
 */
define(["N/record"], function (r) {
    function deleteRecord(context) {
        r.delete({type: context.type, id: context.id});
    }

    return {each: deleteRecord};
});

As you can see, there's a 1:1 relationship between nlapiDeleteRecord and the delete method of the Record module.

Conclusion

You should now have a solid starting point for working with records in SuiteScript 2.0 using the N/record module!