The Zurich release has arrived! Interested in new features and functionalities? Click here for more

Michael Jones -
Giga Sage

GlideRecord is one of, if not the most, powerful tool at your disposal as a developer in ServiceNow and understanding the basics of using and interacting with it is more or less a prerequisite when dealing with advanced requirements. There are certainly tons of articles and posts covering this topic but none that seem to contain all of the tricks I've picked up over the years, so I thought I'd take some time and put together my own. 

Give "gr" the day off. 

I'll start off with an obvious, yet pervasive bad habit to break and that is always using:

var gr = new GlideRecord('xxxx');

As I mentioned, there are tons upon tons of posts and articles with sample scripts and the vast majority of them use this exact same format. This is fine for an example - it makes sense, helps reinforce what you are demonstrating and keeps samples somewhat consistent, but as a practice within your instance it's a bad idea. While it is true, as long as a variable name is unique within a script there is no technical reason you can't use gr, it is always a best-practice to keep variable names descriptive and meaningful. As a compromise I suggest at least appending a table name or record prefix to remind you what you are looking at. For example:

var gr_INC = new GlideRecord('incident');
or
var gr_sys_email = new GlideRecord('sys_email');

 *Bonus Hint, if you copy some sample code into a script field within ServiceNow, double-click on one instance of gr (to highlight it) and click ctrl + ; you will invoke replace-all. Hit enter, type your new variable name, and you should replace all instances at once. I do this in a separate (blank, new) record from the one where I want to use the copied script to void any accidental replacements). 

When you can, go get'em!

Whenever you have the sys_id of a specific record that you need to query for, you can skip a lot of the hassle by just using .get()

For example, if you have a reference field on a form named config_item that reference cmdb_ci and need to return attributes in a script you can use this:

var gr_ci = new GlideRecord('cmdb_ci');
gr_ci.get(current.config_item);
var assignment_group = gr_ci.assignment_group;


Instead of going through the extra steps I often see like:

var gr_ci = new GlideRecord('cmdb_ci');
gr_ci.addQuery('sys_id', current.config_item.sys_id);
gr_ci.query();
if(gr_ci.next()) {
    var assignment_group = gr_ci.assignment_group;
}

 

Ok - you've probably seen that before, at least somewhere. Did you know, however, that .get() can be used in more ways than just with a sys_id? That's right! This function will actually accept two parameters.

The first parameter is the name of the field that you want to search and the second parameter is the value to search for and behaves somewhat differently based on whether the value you pass is unique.

For example, for an incident where you have the number, you can use something like this: 

var gr_incident = new GlideRecord('incident');
gr_incident.get('number', 'INC0010076');
var desc = gr_incident.description;

In this case .get() will behave exactly as before, returning one record. 

If, however, you use something like this:

var gr_incident = new GlideRecord('incident');
gr_incident.get('category', 'software');

gr_incident will contain a result set of all incidents with a category of software. In this case, you can use .next() to cycle through results.

var gr_incident = new GlideRecord('incident');
gr_incident.get('category', 'software');

while(gr_incident.next()) {
gs.info(gr_incident.number);
}

This means that, if you have a query with just one argument where field = value, you can use .get() as shorthand instead of .addQuery() and .query(). 

Dot Walk inside your Glide Query

Have you ever been in a situation like this; you need to query all of the incidents assigned to a particular group, where you only have the group name and the value changes dynamically? I see situations like this arise often and many solutions would have you first take the name of the group, use GlideRecord to lookup the sys_id, and then query the incident table for any records where assignment_group = the sys_id. 

That certainly works, but what isn't entirely obvious is that it's not necessary to perform that first lookup. Instead you can Dot Walk directly in the query on incident, like this: 

var groupName = 'Service Desk'; //name of the group

var gr_INC = new GlideRecord('incident');
gr_INC.addQuery('assignment_group.name', groupName); //dot walk to the name
gr_INC.addActiveQuery();
gr_INC.query()

while(gr_INC.next()) {
gs.info(gr_INC.number + ':' + gr_INC.assignment_group.name);
}

GlideFilter.checkRecord() - you little match-maker you! 

Ok, while not "technically" part of GlideRecord itself, this little utility can be an enormous time-saver. GlideFilter basically gives you a way to check if a particular record in a GlideRecord query matches the condition (query) that you provide. So, how does this help?

Let's say you want to look at all P1 incidents that have been open for more than an hour and take some action to escalate them (send a notification), but let's say that you want to take some additional action if the assignment group is a certain value and even more drastic action if the user is flagged as a VIP. You could break that down into three queries, going from broad to more specific, taking action - or you could consolidate them, using GlideFilter. 

var gr_INC = new GlideRecord('incident');
gr_INC.addQuery('priority', 1);
gr_INC.query();
while(gr_INC.next()) {
	
	//take an action, because this is a P1
	
	//Check if the incident is assigned to the Service Desk
	if(GlideFilter.checkRecord(gr_INC, 'assignment_group.name=Service Desk')) {
		
		//take an action because the incident is assigned to the Service Desk
		
	}
	
	//Check if the caller is flagged as a VIP
	if(GlideFilter.checkRecord(gr_INC, 'caller_id.vip=true')) {
		
		//Take an action because the caller is a VIP
		
	}
	
}

 This can really help to optimize code!

GlideFilter can can be used in pretty much any situation where you want to take a list of records and then check to see if a specific record matches additional criteria. I didn't really know about or understand this option for years, but once I figured it out I've yet to find an end to uses for it!

The difference between "gr.sys_id" and "gr.getValue('sys_id')"

On the surface, both of these seem to return the same result, which can make it frustrating when you seem to "suddenly" encounter an issue where you run a query to gather data from multiple records, but only seem to be getting data from one record. To add insult to injury, it seems to be the last record in the query set. By the way, while I'm using sys_id as an example, this applies to any any field on a GlideRecord. 

The difference between these two lines is that "gr.sys_id" is a pointer and gr.getValue('sys_id') is a result.

If you were to iterate through a query, pushing "gr.sys_id" to an array, the end result would be an array with multiple entries of the same sys_id - the last one processed through your loop. Think of "gr.sys_id" as a bookmark, it opens the same page every time, but the content is whatever was last loaded to the server.

Using "gr.getValue('sys_id')" on the other hand is like taking a snap-shot of a web page and saving it offline. Even if they update the site ten seconds later, the copy you saved remains intact and accessible the way it was. 

For many situation you will find no impact or difference between using .sys_id or .getValue('sys_id), but recognizing when you can use one vs. the other can be challenging and frustrating. I would therefore recommend using .getValue() as a habit because, in my experience, it always works. 

As a bonus, using .getValue() comes with the added advantage of allowing you to dynamically pass the name of the field you want the value of, instead of hard-coding it. Just assign the name of the field to a string and pass the string as the argument for .getValue(). This is particularly useful when creating GlideAjax functions as it allows you to be more flexible in what you are able to return, using the same framework without having to write specific functions.  

The missing link....

Oh wait, here it is! Ever had a situation where you want to easily construct a link directly to a record out of your GlideRecord set? Well, you can!

var gr_incident = new GlideRecord('incident');
gr_incident.get('number', 'INC0010076')

gs.info(gs.getProperty('glide.servlet.uri') + gr_incident.getLink());

 

A few uncommonly used features that can come in handy

Every so often I come across a feature that is useful, interesting, or that I just find preferable. I personally prefer anything that saves a few key strokes when I'm coding so: 

var gr_Users = new GlideRecord('sys_user');
//Note, don't try all of these at once!

gr_Users.addQuery('vip=true^notification=2'); //Did you know, if you pass an encoded query string to addQuery(), it acts the same as .addEncodedQuery()

gr_Users.addActiveQuery(); //you've probably seen this one, it's the same as .addQuery('active, true);

gr_Users.addInactiveQuery() //similar to above, but replaces .addQuery('active', '!=', true);

//Say you want to find all users that belong to ACME South America or ACME UK. 
//You could write two lines to include an or condition, but could also instead use:
 
gr_Users.addQuery('company.name', 'ACME South America').addOrCondition('company.name', 'ACME UK');

 

Honestly, if one were so inclined, you could write a decent sized book on the subject of GlideRecord and all of its nuances and vagaries but, that's all for now! Hopefully you gleaned something useful, cool or neat from my eclectic ramblings!

If you found this article helpful or useful, please be kind and click appropriately. If you found it really useful, you could always use the 3-dot menu to bookmark it for later! 

Michael Jones - Proud member of the Cloudpires team!

 

Comments
anaghas
Tera Contributor

Great tips and hints that comes handy for developers. Thanks much for sharing. Looking forward to your next post!

David333
Giga Contributor

Good stuff! I'm just getting started and I can already see where some of this can be put to use. Nice one with creating a link! On question though - what is up with the 3 dot thing at the end? Just curious!

Michael Jones -
Giga Sage

The functionality is basically to add the article under your forum bookmarks (under your profile) and to subscribe (get notified of updates). Me mentioning it was a "shameless plug" as it awards me forum points if you mark as helpful, and more points if you also bookmark.  Thanks for the feedback!

Hemant Goldar
Mega Sage
Mega Sage

Perfect Article!

servicenowtim
Tera Contributor

I'm a beginner at the moment, currently going down the rabbit hole after thinking of an idea for my PDI. I had a few 'ah ha!' moments that just clicked with me. Thank you very much.

Daniel Oderbolz
Kilo Sage

@Michael Jones -thanks for this good article!

Just an input concerning .get:

- if should always be used in an If statement (might not work!)

- if the column you use in the 2-parameter option does not exist, the get fetches all rows

Slava Savitsky
Giga Sage

Are you sure

 

addInactiveQuery()

 

translates to

 

addQuery('active', '!=', true)

 

?

 

Or is it rather

 

addQuery('active', false)

 

?

Version history
Last update:
‎01-28-2020 05:56 AM
Updated by: