Understanding addNullQuery Usage: A Complete Guide






Mastering addNullQuery: A Deep Dive into ServiceNow GlideRecord for Clean Data


Mastering addNullQuery: Your Key to Cleaner Data in ServiceNow with GlideRecord

Ever felt like your ServiceNow instance is hiding secrets, especially when it comes to incomplete or missing data? As developers, we often need to pinpoint records that lack crucial information. That’s where the powerful addNullQuery() method comes into play, a seemingly simple function within ServiceNow’s server-side GlideRecord API that can be a game-changer for data hygiene and targeted scripting.

In this article, we’re not just going to scratch the surface; we’re diving deep. We’ll explore the expansive world of ServiceNow’s Glide APIs, zoom in on the indispensable GlideRecord, and then shine a spotlight on addNullQuery(), showing you its practical applications, how it works under the hood, and how to wield it like a pro.

Agenda: Your Roadmap to GlideRecord Mastery

To truly appreciate the nuance of addNullQuery(), we first need to build a solid foundation. Here’s what we’ll cover:

Glide API Overview: Your Toolkit for ServiceNow Customization

ServiceNow isn’t just a platform; it’s a canvas for customization. And at the heart of every brushstroke are the Glide APIs. These aren’t just fancy terms; they’re collections of pre-built JavaScript classes and methods that let developers interact with the ServiceNow platform, modifying its default behavior and extending existing functionalities. Think of them as your direct line to the platform’s core, allowing you to perform operations that would typically require complex SQL queries, but with the elegance and flexibility of JavaScript.

Each Glide API is a treasure chest of methods, each designed to perform a specific operation, from manipulating forms on the client-side to performing robust database operations on the server-side. They abstract away the complexity, letting you focus on what you want to achieve rather than how the database executes it.

Types of Glide APIs: Client vs. Server – Picking the Right Tool

ServiceNow APIs are broadly categorized based on where they execute:

  • Client-Side APIs: These run in the user’s web browser, typically dealing with user interface interactions, form manipulation, and real-time validation. Examples include:

    • GlideForm (g_form): For interacting with forms.
    • GlideUser (g_user): For retrieving user information.
    • GlideAjax: For asynchronous calls to the server.
    • GlideDialogWindow, GlideList, GlideMenu: For various UI components.
  • Server-Side APIs: These execute on the ServiceNow instance itself, interacting directly with the database, performing complex logic, and handling data persistence. Our focus today, GlideRecord, lives here. Other notable server-side APIs include:

    • GlideSystem (gs): For logging, debugging, and system information.
    • GlideDate, GlideDateTime: For date and time manipulations.
    • GlideAggregation: For performing aggregate queries.
    • GlideElement: For interacting with individual fields.

What is GlideRecord and Its Usage? The Database Whisperer

If ServiceNow had a superhero for server-side scripting, GlideRecord would wear the cape. It’s hands down the most common and vital API you’ll use on the platform. Essentially, GlideRecord is a powerful JavaScript class that provides an object-oriented way to interact with the underlying database, allowing you to perform CRUD operations (Create, Read, Update, Delete) without ever writing a single line of SQL.

Imagine you need to fetch a list of active incidents, update a user’s profile, or create a new change request. Instead of grappling with database-specific syntax, GlideRecord lets you do it all using familiar JavaScript methods. It acts as an abstraction layer, handling both rows (records) and columns (fields) in the database effortlessly. Since we can’t directly hit the database with raw SQL queries in ServiceNow, GlideRecord becomes our indispensable intermediary.

A Crucial Warning: Always Test in Non-Production!
Before you even think about deploying any GlideRecord script to your production environment, test it thoroughly on a non-production instance. An incorrectly constructed query – perhaps a misspelled field name or a logical error – can lead to invalid queries. Running such a query, especially with insert(), update(), or deleteRecord() methods, can have severe consequences, including unintended data loss or corruption. Don’t learn this the hard way!

Key takeaways about GlideRecord:

  • It’s your go-to API for server-side data manipulation.
  • It runs exclusively from the server side.
  • It translates your JavaScript commands into optimized SQL queries behind the scenes.
  • It enables seamless Create, Read, Update, and Delete (CRUD) operations.

GlideRecord Architecture: The JavaScript-to-SQL Translator

At a high level, the GlideRecord architecture is all about abstraction. When you instantiate a GlideRecord object and call its methods, ServiceNow’s platform converts these JavaScript calls into optimized SQL queries, executes them against the database, and then translates the results back into JavaScript objects for you to work with. This means you write elegant JavaScript, and the platform handles the nitty-gritty of database interaction.

GlideRecord API Mapping: Bridging Your Code to the Database

Think of the mapping like a blueprint. Your GlideRecord object represents a table in the ServiceNow database. Each method you call on that object (like addQuery() or update()) maps directly to a specific database operation. This clear mapping ensures that your JavaScript code reliably and predictably interacts with the underlying data structure.
While we don’t have a visual image here, imagine your script on one side, a secure gateway in the middle, and your database tables on the other. GlideRecord is that gateway, ensuring secure and efficient communication.

GlideRecord Methods: A Swiss Army Knife for Data Operations

The list of GlideRecord methods is extensive, making it an incredibly versatile tool. From fetching single records to performing complex queries and bulk updates, there’s a method for almost every data interaction scenario. While we can’t cover all of them here (the reference itself lists over 50!), let’s highlight some essential categories and then zero in on our star player, addNullQuery().

Common GlideRecord Method Categories:

  • Querying: query(), addQuery(), addEncodedQuery(), addActiveQuery(), addInactiveQuery(), addNullQuery(), addNotNullQuery(), addJoinQuery()
  • Navigation & Iteration: next(), hasNext(), get(), chooseWindow()
  • Record Manipulation: initialize(), insert(), update(), deleteRecord(), updateMultiple(), deleteMultiple()
  • Data Retrieval: getValue(), getDisplayValue(), getRowCount(), getTableName(), getUniqueValue()
  • Security & Control: canCreate(), canRead(), canWrite(), canDelete(), autoSysFields(), setWorkflow(), setAbortAction()
Tip: Always test your scripts in the “Scripts – Background” application (accessible via “System Definition > Scripts – Background”) for quick validation and debugging of server-side code. This is where you can see the immediate output of gs.print() or gs.info() statements.

Deep Dive: Understanding addNullQuery() Usage

Now for the star of our show! Among the myriad of querying methods, addNullQuery() and its sibling addNotNullQuery() are incredibly precise tools for data inspection and manipulation.

What Does addNullQuery() Do?

The addNullQuery(fieldName) method is designed to fetch all records where the specified fieldName has a NULL value in the database. In essence, it translates to an SQL WHERE fieldName IS NULL clause.

Why is addNullQuery() Important? Practical Use Cases

You might wonder, “When would I ever need to find null values?” More often than you think!

  • Data Quality and Hygiene: Identifying records that are missing critical information. For example, finding Incidents without an assigned ‘category’ or ‘priority’ can highlight incomplete data entry processes.
  • Process Enforcement: Ensuring that certain mandatory fields are always populated before a record moves to the next stage of a workflow. You can use addNullQuery() to find records stuck due to missing data.
  • Targeted Reporting: Generating reports on records that require follow-up or manual intervention because a key field was left blank.
  • Migration and Integration Validation: After a data migration or integration, you might want to quickly verify if all expected fields have been populated correctly by checking for nulls.
  • Optimizing Workflows: You might have a business rule that should only trigger if a certain field is populated. Using addNullQuery() helps you understand scenarios where that rule might not fire.

Syntax and Example: Finding the Blanks

Using addNullQuery() is straightforward. You simply pass the database column name (field name) as a string argument.

Exercise 32: Displaying records with a null ‘short_description’

Let’s say we want to find all incident records where the short_description field is empty. This could indicate a problem with how incidents are being created or integrated.


var inc = new GlideRecord('incident');
inc.addNullQuery('short_description'); // Find incidents where short_description is NULL
inc.query();
gs.print('Incidents with a NULL short description:');
while (inc.next()) {
    gs.print('Incident Number: ' + inc.number);
}
    

Result: This script will print the numbers of all incident records that currently have a NULL value in their short_description field.

The Counterpart: addNotNullQuery()

Just as useful is addNotNullQuery(fieldName), which does the exact opposite: it fetches records where the specified field is not null. This translates to an SQL WHERE fieldName IS NOT NULL clause.

Exercise 33: Displaying records where ‘short_description’ is not null

Perhaps you need to process only those incidents that clearly have a description.


var inc = new GlideRecord('incident');
inc.addNotNullQuery('short_description'); // Find incidents where short_description is NOT NULL
inc.query();
gs.print('Incidents with a NOT NULL short description:');
while (inc.next()) {
    gs.print('Incident Number: ' + inc.number + ' - Description: ' + inc.short_description);
}
    

Result: This will list all incident numbers along with their short descriptions, but only for those records where the short description is populated.

Troubleshooting addNullQuery()

Sometimes, addNullQuery() might not yield the results you expect. Here are a few things to check:

  • Empty String vs. NULL: This is a common pitfall! A field containing an empty string ('') is not considered NULL by the database. addNullQuery() specifically looks for true database NULLs. If you suspect fields are visually empty but not being caught, they might contain empty strings. You’d need to add another query:

    
    var inc = new GlideRecord('incident');
    var qc = inc.addNullQuery('short_description'); // Condition 1: IS NULL
    qc.addOrCondition('short_description', ''); // Condition 2: IS an empty string
    inc.query();
    // ... process results
                

    This uses addOrCondition() to combine two conditions.

  • Field Name Misspelling: Double-check the field name for typos. ServiceNow field names are case-sensitive. Use the “Configure Dictionary” option on the form to get the exact backend name if unsure.
  • Reference Fields: For reference fields, a null value means no record is linked. addNullQuery('caller_id') would find incidents with no caller assigned.
  • ACLs: Ensure the script’s running context (user) has read access to the table and the field. Even if the field is null, an ACL might prevent you from seeing the record.

Interview Relevance: Why This Method Matters

An interviewer might ask about addNullQuery() for several reasons:

  • Data Integrity Understanding: It demonstrates your awareness of data quality issues and how to programmatically identify them.
  • Querying Nuance: It shows you understand the difference between NULL and an empty string, a common source of bugs.
  • Problem-Solving: Explaining scenarios where you’d use it (e.g., finding incomplete records for a data cleanup project) showcases practical problem-solving skills.
  • Efficiency: It’s a more efficient and readable way to query for nulls than trying to construct an encoded query like 'short_descriptionISEMPTY' (though encoded query is also valid, this method is more explicit).

Practical GlideRecord Exercises: Putting Knowledge into Action

Now that we’ve grasped the core of GlideRecord and the specificity of addNullQuery(), let’s explore a few more common and illustrative exercises to round out your understanding. These examples demonstrate the breadth of GlideRecord’s capabilities.

1. Basic Output and Variable Handling (gs.print()/gs.info())

Before querying, how do we even see output? gs.print() (or gs.info()) from the GlideSystem API is your best friend for debugging in “Scripts – Background.”


gs.print('Welcome to ServiceNow Academy'); // Simple text output
gs.info('Current script execution started.'); // Use gs.info for better logging categorization
    

Result: Displays “Welcome to ServiceNow Academy” and “Current script execution started.” in the output panel.

2. Working with query() and next(): Iterating Through Records

The most fundamental way to retrieve multiple records. query() executes the query, and while(gr.next()) iterates through the results.


var inc = new GlideRecord('incident');
inc.query(); // Executes the query to fetch all incidents
gs.print('All Incident Numbers:');
while (inc.next()) { // Loops through each retrieved incident record
    gs.print(inc.number); // Prints the 'number' field of the current incident
}
    

Result: Prints the incident number of every single record in the Incident table.

3. Refining Queries with addQuery(): Targeting Specific Records

addQuery() is how you filter your results, much like an SQL WHERE clause.

Exercise 1: Display priority-1 tickets from the incident table


var inc = new GlideRecord('incident');
inc.addQuery('priority', '1'); // Filters for records where 'priority' field equals '1'
inc.query();
gs.print('Priority 1 Incidents:');
while(inc.next()){
    gs.print(inc.number);
}
    

Result: Prints only the incident numbers for records with a priority of ‘1’ (Critical).

4. Chaining Multiple Queries: Combining Conditions

You can chain multiple addQuery() calls, which act as an AND operator.

Exercise 2: Active, Priority 1, Software Category Incidents


var inc = new GlideRecord('incident');
inc.addQuery('active', true); // Condition 1: active = true
inc.addQuery('priority', '1'); // Condition 2: priority = 1
inc.addQuery('category', 'software'); // Condition 3: category = software
inc.query();
gs.print('Active, P1, Software Incidents:');
while(inc.next()){
    gs.print(inc.number);
}
    

Result: Prints incident numbers that satisfy all three conditions.

5. Using addEncodedQuery(): For Complex Filters

When queries become complex, addEncodedQuery() is a lifesaver. You can copy encoded queries directly from ServiceNow list views.

Exercise 3: Encoded Query for active=true^category=software^priority=1


var inc = new GlideRecord('incident');
inc.addEncodedQuery('active=true^category=software^priority=1'); // Single string for multiple conditions
inc.query();
gs.print('Incidents via Encoded Query:');
while(inc.next()){
    gs.print(inc.number);
}
    

Result: Same as Exercise 2, but using a single encoded string.

6. Using Operators with addQuery('String','Operator','Value')

addQuery() is highly flexible, supporting various operators.

  • Standard Operators: =, !=, >, >=, <, <=
  • String Operators: IN, NOT IN, STARTSWITH, ENDSWITH, CONTAINS, DOES NOT CONTAIN

Exercise 8: Incidents with Category 'Software' or 'Hardware'


var cat = ['software', 'hardware']; // Array of categories
var inc = new GlideRecord('incident');
inc.addQuery('category', 'IN', cat); // Finds records where category is in the 'cat' array
inc.query();
gs.print('Software or Hardware Incidents:');
while(inc.next()) {
    gs.print(inc.getValue('number') + ' - ' + inc.getValue('category'));
}
    

Result: Prints incident numbers and categories for incidents falling under 'software' or 'hardware'.

7. Retrieving Values: getValue() vs. getDisplayValue()

Understanding the difference between actual database values and display values is crucial.

Exercise 19: Printing Display Value of Priority


var inc = new GlideRecord('incident');
inc.addQuery('priority', '1');
inc.query();
while (inc.next()){
    // inc.priority gives the actual value (e.g., '1')
    gs.print('Priority Actual Value: ' + inc.priority + ', Display Value: ' + inc.priority.getDisplayValue());
}
    

Result: For a P1 incident, it might print "Priority Actual Value: 1, Display Value: Critical".

8. Creating New Records: initialize() and insert()

To create a new record, first initialize it, set its field values, then insert.

Exercise 25: Creating a new incident


var inc = new GlideRecord('incident');
inc.initialize(); // Prepares a new, empty incident record
inc.category = 'network'; // Sets the category field
inc.short_description = 'Firewall Issue'; // Sets the short_description field
inc.priority = '1'; // Sets the priority field
var sysId = inc.insert(); // Inserts the new record into the database and returns its sys_id
gs.print('New Incident Created: ' + inc.number + ' with Sys ID: ' + sysId);
    

Result: A new incident record is created with the specified details, and its number and sys_id are printed.

9. Updating Records: update() and updateMultiple()

Modify existing records. Be cautious with these methods!

Exercise 34: Update a single incident's state


var inc = new GlideRecord('incident');
if (inc.get('number', 'INC0000057')) { // Fetches a specific incident by its number
    inc.setValue('state', '2'); // Sets the state field to 'In Progress' (assuming '2' is 'In Progress')
    inc.update(); // Saves the changes to the database
    gs.print('Incident ' + inc.number + ' updated to state: ' + inc.state.getDisplayValue());
} else {
    gs.print('Incident INC0000057 not found.');
}
    

Result: The state of incident 'INC0000057' is updated to 'In Progress'.

10. Controlling System Fields and Workflows: autoSysFields() and setWorkflow()

For advanced scenarios where you need to prevent system fields (like sys_updated_on, sys_updated_by) from being updated or to skip business rules.

Important: autoSysFields(false) prevents updates to system fields but is generally not recommended in scoped applications. setWorkflow(false) prevents business rules, flows, and other workflow elements from running for that update. Use these with extreme caution, as they can bypass critical platform logic.

var inc = new GlideRecord('incident');
inc.addQuery('state', '1'); // Find incidents in 'New' state
inc.query();
while (inc.next()) {
    inc.autoSysFields(false); // Do NOT update sys_updated_by, sys_updated_on, etc.
    inc.setWorkflow(false);   // Do NOT trigger Business Rules, Flows, etc.
    inc.setValue('state', '2'); // Change state to 'In Progress'
    inc.update();
    gs.print('Updated incident ' + inc.number + ' without system field updates or workflows.');
}
    

Result: Incidents in 'New' state are moved to 'In Progress', but the audit fields won't change, and no business rules (e.g., email notifications) will fire for this update.

Troubleshooting Common GlideRecord Issues: When Things Go Wrong

Even with a firm grasp of GlideRecord, you'll inevitably hit bumps. Here's a quick guide to common issues and their solutions:

  • No Records Found (or Too Many):

    • Check your query: Is the field name correct (case-sensitive)? Is the value correct? Are you using the right operator?
    • Data type mismatch: Are you comparing a string to a number? Use toString() or parseInt() if necessary.
    • Active/Inactive state: Are you expecting active records but retrieving inactive ones, or vice versa? (e.g., using addActiveQuery()).
    • Permissions (ACLs): Does the user executing the script have read access to the records and fields?
  • Performance Problems (Slow Scripts):

    • Missing setLimit(): If you only need a few records, don't fetch thousands. Always use setLimit() for large tables or when iterating.
    • Unindexed fields: Querying on unindexed fields can be slow. Check your table's dictionary.
    • Too many `next()` calls: Avoid large loops on huge datasets. Consider updateMultiple()/deleteMultiple() for bulk operations.
    • addJoinQuery() overuse: While powerful, join queries can be resource-intensive.
  • Accidental Data Changes:

    • Not testing in non-prod: We've said it before, but it's critical.
    • Wrong query: An incorrectly written query paired with an update() or delete() method can lead to disaster. Always verify your gs.print() output of affected records *before* adding the destructive methods.
    • Missing gr.initialize() for new records: If you try to insert() without initialize(), you might update an existing record if its sys_id was somehow set.
  • Unexpected Workflow/Business Rule Behavior:

    • setWorkflow(false): If your updates aren't triggering expected email notifications or related actions, check if this was accidentally set.
    • Order of operations: Business rules and client scripts run at specific times. Ensure your server-side script is executing when expected relative to other platform logic.

Interview Relevance: Why This Matters for Your Career

Mastering GlideRecord isn't just about writing functional code; it's about demonstrating a deep understanding of ServiceNow's core architecture and best practices. Interviewers will often probe your GlideRecord knowledge for several reasons:

  • Foundational Skill: It's the bedrock of server-side customization. If you can't use GlideRecord effectively, your capabilities as a ServiceNow developer are limited.
  • Problem-Solving Aptitude: Questions about specific methods like addNullQuery(), addEncodedQuery(), or updateMultiple() assess your ability to choose the right tool for a specific problem.
  • Performance Awareness: Discussing setLimit(), efficient querying, and avoiding unnecessary loops shows you're mindful of instance performance, a critical aspect of enterprise development.
  • Data Integrity Focus: Being able to explain how to manage data quality (e.g., finding nulls, handling empty strings) highlights your attention to detail and responsible coding.
  • Debugging Skills: Describing how you troubleshoot GlideRecord issues (using gs.info(), checking logs, isolating queries) showcases your practical debugging prowess.

Be prepared to discuss scenarios, explain the difference between methods (e.g., get() vs. query(), getValue() vs. getDisplayValue()), and articulate why certain practices are considered "best."

Conclusion: Embracing the Power of Precision Querying

The ServiceNow platform, with its robust Glide APIs, empowers developers to build incredible solutions. At the core of this power lies GlideRecord, your essential tool for interacting with the database. We've explored its vast capabilities, from basic CRUD operations to advanced query techniques.

Specifically, we've shone a light on addNullQuery(), demonstrating its crucial role in maintaining data quality, validating integrations, and refining your application logic. It might seem like a small piece of the puzzle, but understanding how to precisely identify and handle records with null values is a hallmark of an experienced and effective ServiceNow developer.

Keep practicing these methods, experiment in your personal developer instance, and remember the golden rule: test, test, test! Your journey to becoming a GlideRecord master is well underway. Happy scripting!


Scroll to Top