Mastering `getRowCount()` in ServiceNow: Your Go-To Guide for Counting Records Like a Pro
Alright, let’s talk numbers! In the vast, intricate world of ServiceNow, sometimes you just need to know how many. How many active incidents do we have? How many users are in a specific group? How many knowledge articles are pending review? The ability to accurately and efficiently count records is fundamental, not just for reporting, but for data validation, conditional logic in scripts, and even for performance optimization.
That’s where the trusty getRowCount() method comes into play. If you’ve spent any time scripting in ServiceNow, you’ve likely bumped into it. But like many simple-looking tools, there’s more to getRowCount() than meets the eye. It’s powerful, incredibly useful, but also comes with nuances and considerations you’ll want to master. Let’s dive deep and make sure you’re using it like a seasoned pro.
This article will guide you through the essentials, uncover practical applications, address common pitfalls, and even touch upon how knowing this method can make you shine in your next ServiceNow interview. Ready? Let’s get counting!
The Core Concept: Understanding getRowCount()
At its heart, getRowCount() is a method of the GlideRecord object in ServiceNow. Its sole purpose is to tell you how many records were found by your query. Simple, right? But the key is that it only works after you’ve executed your query. Think of it like this: you tell the database what you’re looking for, then you ask it, “So, how many did you find?”
What is GlideRecord? A Quick Refresher
Before we dive into getRowCount(), let’s quickly recap GlideRecord. It’s arguably the most fundamental API in ServiceNow scripting, allowing you to interact with the database. It lets you query, insert, update, and delete records from any table in your instance. Every time you want to get data out of a table, you’re probably starting with var gr = new GlideRecord('table_name');.
The Anatomy of a Basic Count
Let’s look at the most straightforward way to use getRowCount(), as demonstrated in our reference material:
var inc = new GlideRecord('incident');
inc.query();
gs.print(inc.getRowCount());
Let’s break down each line:
var inc = new GlideRecord('incident');: This line creates a newGlideRecordobject, specifically targeting the ‘incident’ table. It’s like telling ServiceNow, “Hey, I’m interested in incidents!”inc.query();: This is the magic handshake with the database. Without any specific conditions (which we’ll add in a moment), this line tells ServiceNow to fetch *all* records from the ‘incident’ table. It executes the query and populates theGlideRecordobject with the results. This step is crucial;getRowCount()will not work correctly without it.gs.print(inc.getRowCount());: Finally, after the query has run, we ask ourincobject, “How many records did you find?” ThegetRowCount()method returns an integer, whichgs.print()then displays in the background script output, a UI Action info message, or a server-side log, depending on where your script runs.
Result: If you run this in a background script, you’ll see a single number printed, representing the total count of all incident records in your instance. Pretty neat, right?
Pro Tip: While gs.print() is traditional, modern ServiceNow scripting often favors gs.info(), gs.debug(), or gs.warn() for logging, as they offer better control over log levels and are visible in the System Logs application (syslog.do), making debugging easier in real-world scenarios.
Precision Counting: Filtering Your Results
Counting all records in a table is useful for auditing, but more often than not, you’ll need to count a specific subset of records. This is where filtering comes in, and getRowCount() works beautifully with it.
Using addQuery() for Targeted Counts
Our second reference example perfectly illustrates this:
var grUsers = new GlideRecord('sys_user');
grUsers.addQuery('active', true); // or 'active=true' as a string
grUsers.query();
gs.print ('Active users are: ' + grUsers.getRowCount());
Let’s break this down:
var grUsers = new GlideRecord('sys_user');: We’re now targeting the ‘sys_user’ table, which holds all user records.grUsers.addQuery('active', true);: This is the filter! We’re telling ServiceNow, “Only consider users where the ‘active’ field is set to ‘true’.”addQuery()is super flexible. You can use it with two arguments (field name, value) or three (field name, operator, value), or even a single string like'active=true'.grUsers.query();: Again, we execute the query. Now, instead of fetching ALL users, it only fetches those matching our ‘active=true’ condition.gs.print ('Active users are: ' + grUsers.getRowCount());: And finally, we get the count of only the active users.
Result: You’ll see something like “Active users are: [Number]” in your output, where [Number] is the count of active users in your instance.
Combining Multiple Filters
The real power of addQuery() (and its sibling addEncodedQuery()) shines when you need to layer multiple conditions. getRowCount() will count records that satisfy *all* your specified conditions (an implicit AND operator).
Imagine you want to count active users who also belong to a specific company:
var grActiveCompanyUsers = new GlideRecord('sys_user');
grActiveCompanyUsers.addQuery('active', true);
grActiveCompanyUsers.addQuery('company.name', 'ACME Corp'); // Assuming 'company' is a reference field to 'core_company'
grActiveCompanyUsers.query();
gs.print('Active users from ACME Corp: ' + grActiveCompanyUsers.getRowCount());
This script would give you a precise count of active users specifically associated with ‘ACME Corp’. See how quickly we can narrow down our focus?
Why getRowCount() is a Real-World Hero
Knowing how to use getRowCount() is one thing, but understanding when and why it’s invaluable is what truly elevates your ServiceNow game. It’s not just a fancy trick; it’s a fundamental building block for countless automation and data management tasks.
1. Dynamic Reporting and Dashboards
While ServiceNow’s out-of-the-box reporting is robust, sometimes you need a quick, script-driven metric for a custom dashboard widget or a server-side report generation. getRowCount() is perfect for this. You can easily create a script include that returns specific counts, which can then be displayed anywhere.
// Example: Script Include function to get critical open incidents
function getCriticalOpenIncidentCount() {
var gr = new GlideRecord('incident');
gr.addQuery('active', true);
gr.addQuery('priority', 1); // Priority 1 = Critical
gr.query();
return gr.getRowCount();
}
// In a widget or business rule:
// var criticalCount = new MyUtils().getCriticalOpenIncidentCount();
// gs.info('Critical Open Incidents: ' + criticalCount);
2. Data Validation and Prevention
Imagine you have a requirement that there should never be more than one “Urgent” change request open at a time. Before creating a new “Urgent” change, you can use getRowCount() to check this condition.
// In a Before Insert/Update Business Rule on the Change Request table
if (current.priority == '1 - Critical' && current.state != '3 - Closed') { // Assuming 'Critical' is defined by priority 1
var grCR = new GlideRecord('change_request');
grCR.addQuery('priority', '1 - Critical');
grCR.addQuery('state', '!=', '3 - Closed'); // Not closed, so still open or in progress
grCR.addQuery('sys_id', '!=', current.sys_id); // Exclude the current change if it's an update
grCR.query();
if (grCR.getRowCount() > 0) {
gs.addErrorMessage('Cannot create/update: Another Critical Change Request is already open.');
current.setAbortAction(true);
}
}
This is a powerful way to enforce business rules and maintain data integrity.
3. Conditional Logic in Workflows and Flows
While Flow Designer and Workflow activities often have their own ways to count (e.g., “Look Up Records” action with a count property), sometimes you need more granular control in a script step. You might want to branch a workflow based on whether a certain threshold of records is met.
// In a workflow script or Flow Designer script step
var highPriorityTasks = new GlideRecord('sc_task');
highPriorityTasks.addQuery('request_item', current.sys_id); // Tasks for the current RITM
highPriorityTasks.addQuery('priority', '1 - Critical');
highPriorityTasks.query();
if (highPriorityTasks.getRowCount() > 2) {
// If more than 2 critical tasks, escalate to a manager
gs.info('Too many critical tasks for RITM ' + current.number + '. Escalating!');
// return 'escalate'; // For workflow branching
} else {
// Proceed normally
// return 'normal';
}
4. Troubleshooting and Debugging
Quickly verify if your query conditions are actually returning the data you expect. If you think your query should return 5 records but getRowCount() shows 0, you immediately know there’s an issue with your query parameters or the data itself.
// Debugging a complex query
var grProblem = new GlideRecord('problem');
grProblem.addEncodedQuery('active=true^priority=1^assignment_group=javascript:getMyGroups()');
grProblem.query();
gs.info('Problems found: ' + grProblem.getRowCount()); // Quick check to see if the query yields results
Advanced Scenarios and Best Practices: When to Use (and Not Use) getRowCount()
Okay, we’ve covered the basics and common use cases. Now let’s elevate our understanding. getRowCount() is fantastic, but like any powerful tool, it needs to be used wisely, especially when performance is a concern.
Performance Considerations: Small vs. Large Datasets
For small to moderately sized tables, or queries that return a limited number of results (tens, hundreds, maybe even a few thousand), getRowCount() is generally efficient. It makes a database call to fetch the record metadata (or the records themselves, depending on internal GlideRecord optimizations) and then provides the count.
However, when you’re dealing with very large tables (hundreds of thousands, millions of records) and your query is broad, using getRowCount() can become a performance bottleneck. Why? Because GlideRecord.query() fetches the actual records (or at least enough information to iterate through them) into memory on the application node before getRowCount() can determine the total. This can be resource-intensive.
Performance Warning: Avoid running getRowCount() on very broad queries against massive tables in highly transactional or performance-critical scripts (e.g., frequently triggered business rules, heavily used UI Actions) without careful consideration. It might lead to slow scripts or even instance performance degradation.
When to Consider Alternatives: Introducing GlideAggregate
For truly massive counts or when you need to group counts (e.g., “How many incidents per assignment group?”), GlideAggregate is your best friend. GlideAggregate is designed for database aggregation functions (COUNT, SUM, AVG, MIN, MAX) and performs these operations at the database level, often much more efficiently than GlideRecord, especially for large datasets. It avoids pulling all individual records into the application node’s memory.
// Using GlideAggregate to count incidents
var ga = new GlideAggregate('incident');
ga.addAggregate('COUNT'); // We want to count
ga.query(); // Execute the query
var incidentCount = 0;
if (ga.next()) {
incidentCount = ga.getAggregate('COUNT');
}
gs.info('Total incidents (via GlideAggregate): ' + incidentCount);
// To get grouped counts, e.g., incidents per state:
var gaState = new GlideAggregate('incident');
gaState.addAggregate('COUNT', 'state'); // Count by state
gaState.groupBy('state'); // Group the results by state
gaState.query();
while (gaState.next()) {
var stateName = gaState.state.getDisplayValue();
var count = gaState.getAggregate('COUNT', 'state');
gs.info('Incidents in state "' + stateName + '": ' + count);
}
Key takeaway: If you just need a simple count of records matching specific criteria, and the dataset isn’t astronomically huge, getRowCount() is perfectly fine. If you’re dealing with millions of records or need aggregated data (sums, averages, grouped counts), lean towards GlideAggregate for better performance.
The Interaction with setLimit()
GlideRecord.setLimit(n) restricts the number of records returned by a query. If you use setLimit() before query(), getRowCount() will return the number of records up to that limit, not the total number of matching records in the database.
var grLimited = new GlideRecord('incident');
grLimited.addQuery('active', true);
grLimited.setLimit(5); // Only fetch a maximum of 5 active incidents
grLimited.query();
gs.info('Limited count of active incidents: ' + grLimited.getRowCount());
// If there are 100 active incidents, this will print '5'.
// If there are only 3 active incidents, this will print '3'.
This is important to remember. If you need the *actual total count* regardless of how many records you want to process, do not use setLimit() before getRowCount().
What About an Empty Query?
If your addQuery() conditions don’t match any records, getRowCount() will gracefully return 0. This is exactly what you’d expect and is often used in conditional logic: if (gr.getRowCount() > 0) { // Do something }.
Troubleshooting getRowCount() Issues: When Things Go Sideways
Even though getRowCount() seems straightforward, you’ll inevitably run into situations where it doesn’t give you the results you expect. Don’t worry, that’s part of the learning process! Here are some common troubleshooting scenarios:
1. Getting 0 or -1 Unexpectedly
- Incorrect Query Conditions: This is by far the most common culprit. Double-check your
addQuery()statements. Are the field names correct? Is the operator right (e.g.,!=instead of=)? Is the value you’re searching for accurate (case sensitivity, exact match for strings, correct sys_id for references)?// Common mistake: Typo in field name var gr = new GlideRecord('incident'); gr.addQuery('activee', true); // 'activee' instead of 'active' gr.query(); gs.info(gr.getRowCount()); // Will likely print 0 // Common mistake: Incorrect value for reference field var gr = new GlideRecord('incident'); gr.addQuery('assigned_to', 'admin'); // Should be sys_id, not display value by default gr.query(); gs.info(gr.getRowCount()); // Will likely print 0 - Running
getRowCount()Beforequery(): If you forget to callgr.query(),getRowCount()will return-1(in older versions) or0(in newer versions/contexts), as no query has been executed yet to populate the record set. Always ensurequery()precedesgetRowCount(). - ACLs (Access Control Lists): The script might be running in a context where the user (or the system) doesn’t have permission to read the records you’re trying to count. If an ACL prevents read access, those records effectively don’t exist for the query.
- Table Name Typos: A simple mistake like
sys_uservs.sys_userscan lead to zero results. - Scope Issues: If you’re working in a custom application scope, ensure your script has access to the tables you’re querying, or use cross-scope access properly.
2. Performance Lag or Timeouts
- Querying Huge Tables Without Filters: As discussed, `gr.query()` against a table with millions of records without any `addQuery()` conditions can try to pull everything, leading to slow performance or even transaction timeouts. Always try to limit your queries.
- Complex or Unindexed Queries: If your query involves multiple `addQuery()` calls on fields that aren’t indexed in the database, it can force a full table scan, which is very slow. While you typically don’t control indexing directly in ServiceNow (SaaS), be aware that complex queries on non-indexed fields are performance killers.
- Looping with `getRowCount()`: Avoid calling `getRowCount()` inside a `while (gr.next())` loop. It’s meant to be called once after `query()`.
3. Unexpected Higher Count
- Missing
addQuery(): You forgot a condition, so it’s counting more records than you intended. For example, you wanted to count active incidents, but forgot to addgr.addQuery('active', true);. - Incorrect Condition Logic: Perhaps you used an OR condition when you meant an AND, or a
!=operator when you meant=.
Debugging Tip: When troubleshooting, always print your query string using gr.getEncodedQuery() before running gr.query() and compare it to what you expect. You can also temporarily add gs.info(gr.getRowCount()); at various stages of your script to isolate where the count is going wrong.
Interview Relevance: Shining with getRowCount() Knowledge
If you’re interviewing for a ServiceNow developer, administrator, or consultant role, expect questions that touch upon fundamental scripting concepts like GlideRecord and database interaction. getRowCount() is a prime candidate for demonstrating your practical scripting knowledge and understanding of best practices.
Common Interview Questions & Expected Responses:
“How would you count the number of active incidents in a script?”
- Expected Answer: “I’d use a
GlideRecordon the incident table, add a query foractive=true, run the query, and then use thegetRowCount()method. For example:”var grInc = new GlideRecord('incident'); grInc.addQuery('active', true); grInc.query(); var activeCount = grInc.getRowCount(); gs.info('Active Incidents: ' + activeCount);
- Expected Answer: “I’d use a
“What’s the difference between
GlideRecord.getRowCount()andGlideAggregate.getRowCount()(or usingGlideAggregatefor counts)?”- Expected Answer: “
GlideRecord.getRowCount()is great for getting a count of records returned by a standardGlideRecordquery, especially for smaller to medium datasets. However, for very large datasets or when needing to perform aggregate functions like counting, summing, or grouping on the database level,GlideAggregateis generally more performant.GlideAggregateprocesses the count on the database server itself, reducing the amount of data transferred to the application node.”
- Expected Answer: “
“When would you not recommend using
getRowCount()?”- Expected Answer: “I’d be cautious using
getRowCount()in performance-critical scripts against extremely large tables without very specific filters, as it can be resource-intensive. In such cases,GlideAggregatewould be my preferred method. Also, if I only need to check if *any* records exist, I might usegr.next()immediately aftergr.query()and thengr.hasNext(), as that might be slightly more efficient if I don’t need the exact number, just presence.”
- Expected Answer: “I’d be cautious using
“What happens if you call
getRowCount()beforequery()?”- Expected Answer: “It won’t work correctly. It will typically return 0 or -1 because no query has been executed to populate the record set yet. The
query()method is essential to fetch the data first.”
- Expected Answer: “It won’t work correctly. It will typically return 0 or -1 because no query has been executed to populate the record set yet. The
By articulating these points, you’re not just showing you know the syntax, but that you understand the underlying mechanisms, performance implications, and best practices – which is exactly what employers are looking for.
Wrapping It Up: Count with Confidence!
So there you have it – a comprehensive tour of getRowCount() in ServiceNow. From its basic usage to advanced considerations, troubleshooting, and interview relevance, you’re now equipped to wield this method with confidence and precision. It’s a testament to the fact that even seemingly simple functions can hold a wealth of depth and practical application in the right context.
Remember, mastering ServiceNow scripting isn’t just about memorizing APIs; it’s about understanding how they interact with the platform, the database, and how they impact performance and user experience. getRowCount() is a fantastic example of a tool that, when understood deeply, can significantly enhance your ability to build robust, efficient, and intelligent solutions.
Keep experimenting, keep learning, and keep counting! Your ServiceNow journey is an exciting one, and every method you master brings you closer to becoming a true platform expert.