white notes beside a pencil on brown wooden surface

For quite some time now we can use a modern version of data retrieval class – GlideQuery. This post will show you what it is, what are the benefits but also where using it could cause some confusion.

What is GlideQuery?

I encourage you to read some history behind the project. You will understand what has driven the creators of GlideQuery and what they wanted to fix. I believe this should be the very first thing to read.

In short, GlideQuery is a modern and safer interface to query database in ServiceNow. It allows to write readable queries with built-in error handling and descriptive error messages. Since it has been built on top of GlideRecord, it will always be slower in execution. On the other hand, it fails faster – meaning that you will see the error when it occurs and you will also see what has exactly failed.

The biggest advantage and my favourite feature is the fact that you can chain function calls and use well-known native JavaScript methods like filter, forEach, map and couple of others. See the full list in the documentation page. Which, by the way, is very good and full of working examples.

Why it is worth learning it?

First of all, it’s a modern way of retrieving and handling data in ServiceNow. If you want to stay on top of the things and be a good ServiceNow developer, you simply can’t miss it. On the developer blog there are a lot of examples and use cases covering the most important features of this new interface. I won’t repeat all of them, but there are some deserving additional mentions.

Interface usage

When you write a GlideRecord query, it’s simple and basic – you create a variable, assign a query and query the database. Line by line, method by method. However, with GlideQuery it’s a bit different. You use method chaining to get the data and process them.

new global.GlideQuery('incident')
    .where('number', 'INC0010001')
    .select('short_description')
    .forEach(function(inc){
        gs.info(JSON.stringify(inc));
    });

In the example above, you may see the basic example:

  • Line 1 is the interface initialization and contains a table to query
  • Line 2 is the query builder
  • Line 3 is the field selection – you select fields before you use them. This is why GlideQuery fails fast: if the field doesn’t exist, it will fail now
  • Line 4 starts data processing. The inc function parameter represents a single row of data. It is an Object, not a GlideRecord reference! Important to remember since it allows you to safely retrieve the data without using additional methods like getValue

Working with data

The retrieved data is an object. It will always contain the sys_id of the data row – you don’t have to call it directly in select statement. Working with objects is much simpler and easier to read than doing the same with GlideRecord. As you can see, I use JSON.stringify() in the example above.

Handling no data retrieved errors

It’s not always sun and joy, sometimes you may fail to retrieve the data. With GlideReocrd, you had to check for null and use multiple if statements to make sure you cover all scenarios. With GlideQuery, all you need to do is to prepare for such a scenario.

When you use select, you will receive a Stream of records. Then you work on the stream, which can be empty or not, it’s like an array of objects. With select statement, you have to use a terminal method. They are all listed in the documentation page: every(), find(), forEach(), reduce(), some() and toArray(). Otherwise, similary to GlideRecord‘s next(), your query will fail to fetch the data.

But you can also use get() or getBy() to retrieve a single record. GlideQuery handles these with separate class, an Optional. In this case, we have even more data check menthods: ifPresent(), isPresent(), isEmpty() and orElse(). Use these and your code will not only be easy to read but also fool-proof. For example, with orElse() you define your own object values in case nothing is fetched from the database.

Handling other errors

Of course, sometimes you will encounter other errors. The most common typos in field names could cause huge issues in GlideRecord – unintentional updates on thousands of records, because you misspelled a column name in the query? Been there, done that.

Here are some examples that will blow your mind:

Selecting reference display value directly

One of the nice features also covers common task of retriving display value for reference record. You don’t need any new methods or database calls – you can just append $DISPLAY to the reference column in select statement. The only thing to remember is that the result will contain exactly what you wrote in the select:

new global.GlideQuery('incident')
    .where('number', 'INC0010001')
    .select('short_description', 'caller_id$DISPLAY')
    .forEach(function(inc){
        gs.info(JSON.stringify(inc));
    });
 // will give you the following result:   
 {"short_description":"test","caller_id$DISPLAY":"Cezary BASTA","sys_id":"4088e6b01b66f510e480ec22604bcb55"}

Best practices

And finally, one of my favourite thing with GlideQuery – it was designed with best practices in mind, that’s why you don’t have to bother anymore. It already uses everything that was ever recommended to do with GlideRecord.

The confusing bit

So I promised to write something about confusion… Yes, it’s not always obvious what and why you would receive.

It’s pretty common to fetch single records with get() or getBy(). When you are not careful, you may see some unexpected results (similarly to reding field values from GlideRecord with a dot vs using getValue()).

Let’s see an example. This works fine:

But surprisingly, when you remove the orElse() call, you will get something else:

It gets more confusing when you take a look at orElse() documentation page: Adds a default value within the Optional object if the query does not return any results. But we know that our query returns something! Why? Because, contrary to get(), getBy() is not a terminal method. You can read about it in the documentation.

OK, so now we know this, what do you think will be the result of getBy() for a record that doesn’t exist?

And without orElse()? I believe you expect the same result as querying for existing record?

I was expecting it too

Conclusion

GlideQuery is a must-know for ServiceNow developers. It provides a modern, fast, reliable, best-practice friendly way to fetch ServiceNow data. In case of errors, it gives great messages. You just have to read the documentation a lot and get familiar with the concept of terminal methods and when to use them.

So…

Leave a Reply

Your email address will not be published. Required fields are marked *