Andrew Barnes

7 minute read

GlideRecord

To start the new year, I want to dive into the depths of the GlideRecord object and how this information can make you a better developer. This article will be at a reasonably advanced level but should be valuable for most any level of ServiceNow developer. We will utilize a variety of tools to expose the details of GlideRecord under the hood.

The easiest way to inspect the details of the fields and values that are available to the GlideRecord object and when they are available is the script debugger. We will start by creating a business rule which will be used to hold our script, and be invoked in order to inspect the values in the script debugger. As a quick reminder, the script debugger can only be used in a synchronous script that is run in the current user’s session. That is why a business rule is the method of choice for our examples.

var incidents = new GlideRecord('incident');
incidents.addActiveQuery();
incidents.addQuery();
incidents.setLimit(2);
incidents.query();
while(incidents.next()){
  //dothings on the results
}

Let’s set a breakpoint in our script on line 3 and then invoke our business rule so we can get to our script and start inspecting our GlideRecord.

Break Point

As you step through the lines, you can watch what the debugger has for the incidents object. At first, you will see that it is undefined until we execute the incidents.query() line where it becomes an empty incident GlideRecord object and a pointer to just before the first results.

Meta Data

See what happens when we allow incidents.next() to execute which means the debugger pointer has moved past it. Until we have executed our first .next() we are pointing right before our first returned record result. The .next() moves us forward to the next returned result. We can’t directly enumerate over these GlideRecord objects, but under the hood, ServiceNow is doing so. There are methods to move around the returned results in a non-linear manner that I might cover later.

After Next

So, let us examine our incidents object in the debugger now that we have executed the .next() command and loaded the first matching result for our query. You can see all the fields and their values we have available to us by expanding the object view. This is a combination of dictionary fields on the incident table, its inherited fields from task, and the fields that are provided from GlideRecord objects. You might want to take special note of some of these, like variables that are not directly on the incident table. When our loop gets to the end, and we move back up to the .next() line and execute it again, we move to the next ordered result returned for our query.

GlideRecord Details

Queries

Each developer has their method for building queries. Some choose to write them with .addQuery(‘field’, value) some choose to use .addEncodedQuery() and others choose a combination. My personal preference is to build my query in the list view and use the copy query on the breadcrumbs then take that and break it down into parts for easy readability.

Get the Query

sys_created_onONToday@javascript:gs.beginningOfToday()@javascript:gs.endOfToday()^short_descriptionSTARTSWITHthe name^ORshort_descriptionLIKEis4^assignment_groupISEMPTY

Above we have the query I have chosen to use. It looks pretty intimidating when bunched all together, but if you break it up at the ^ or ^OR which represents AND and OR it is much more readable.

Line Breaks for Query

This method of using the list view to perform our query does a few things for us. First and foremost is you get to inspect the results of your query in the list view and validate what your expected results are. Additionally, it helps remove any typo’s and need to verify all the field dictionary names. The use of a variable and layout method is just a personal preference for readability.

Performance

Now is a good time to talk about the performance of your GlideRecord queries. Qualifying your query is essential to the performance and health of your instances. Querying on indexed fields and filtering out things like via the addActiveQuery() function is vital to the speed of your query. One large wasteful performance issue that comes up routinely is using a GlideRecord query to get a row count. If you are not going to work directly with the returned result objects its much faster and better to use GlideAggregate when you only need a count. I will publish a more detailed post just on performance soon.

GlideRecord Elements

Back to the components of our GlideRecord. The fields of your object are called GlideElements. There are quite a few functions that are available on these GlideRecord Elements that you can utilize to interact with those objects. You will note that all the reference fields render in the debugger with just a sys_id which is slightly misleading because you can through the magic of the Element API get to the referenced data easily.

var managers = [];
var incidents = new GlideRecord('incident');
incidents.addActiveQuery();
incidents.addQuery();
incidents.setLimit(2);
incidents.query();
while(incidents.next()){
  managers.push(incidents.caller_id.getDisplayValue('manager'));
}

We have an array for the manager’s names which will demonstrate a common error many newer devs fall into when looping over the results and trying to place the results into an array. If you do a direct: managers.push(incidents.caller_id.manager.name); you will end up with multiple entries of the same name in your array. The Element API allows us to do things like getting values and not just pointers to values which can and will likely change when a .next() is executed.

While you can dot-walk down multiple levels of referenced fields, it is my preference to work with the target referenced object directly if I need more than one field at a time. Which highlights another useful API - getRefRecord. Here are some examples of how you could do the same work with different methods.

while(incidents.next()){
        incidents.caller_id.getDisplayValue('manager');
        incidents.caller_id.manager.getDisplayValue('department');
        incidents.caller_id.manager.getValue('phone');
        incidents.caller_id.manager.getValue('title');
        
        var managerGR = new GlideRecord("sys_user");
        managerGR.addQuery("sys_id", incidents.caller_id.manager.getValue('sys_id'));
        managerGR.query();
        if (managerGR.next()) {
            managerGR.getDisplayValue();
            managerGR.getDisplayValue('department');
            managerGR.getValue('phone');
            managerGR.getValue('title');
        }
        
        var managerGet = new GlideRecord("sys_user");
        managerGet.get(incidents.caller_id.manager.getValue('sys_id'));
        managerGet.getDisplayValue();
        managerGet.getDisplayValue('department');
        managerGet.getValue('phone');
        managerGet.getValue('title');
        
        var manager = incidents.caller_id.getRefRecord('manager');
        manager.getDisplayValue();
        manager.getDisplayValue('department');
        manager.getValue('phone');
        manager.getValue('title');
        
    }

The above is by no means a complete list of how you can get the managers name, department, phone, and title. I prefer the last entry for how quickly and clearly the script is understood. Using getRefRecord returns me a GlideRecord object which I can use just as I would from performing a full query in the managerGR example above. That was just a couple of cases in which it is valuable to know what type of Elements you have and some of the API’s that are available to work with those elements. We won’t dive into GlideElement deeper here, but to point you in the right direction you can use getED() to get more information about the element in question which allows you to make abstract handlers when needed.

Return to GlideRecord

Speaking of having more knowledge of the object in question it is useful to know more about our GlideRecord. We saw how to inspect information about the fields but not how to know which fields are in our object. Another way outside of the script debugger we were using above to examine what fields are available is getFields(). Here is an example of how to get all the current objects fields, print them out, and iterate over each one if we wish to get more detailed information from them.

var fields = current.getFields();
gs.print(fields);
for (var num = 0; num < fields.size(); num++) {

Getting the elements and inspecting them is useful. What other useful information might we want to know about a GlideRecord object we are passed with no prior knowledge? The table is it a valid object, what query was used, and more. Thankfully getTable(), isValidRecord(), getEncodedQuery(), and more exist for us to interact with unknown GlideRecord objects. Since we have been working with a business rule, we should check out a few functions and their common uses.

current.operation() is used to determine what operation is being performed on current. Insert, update, or delete. That knowledge allows us to make a generic business rule which can handle all three operations but might have just a little extra handling for the delete case. Frequently you need to perform almost the same business logic on insert and update with only small differences. Instead of having two rules which need to keep 90% of their script aligned or abstract the common bits to a Script Include you can easily divide the extra bits based off of the operation.

More to come

Hopefully, this gives you some information and more importantly the tools and knowledge to learn the API’s and probe the depths of GlideRecord. Blog entries on performance and building queries will be coming out in the future. To listen and watch more detail about GlideRecord you can watch Community MVP Steven Bell on the ServiceNow Community YouTube. Many of the API’s are directly linked in the article, but you can find and get examples for those and more here.


Comments