Use GlideAggregate Instead of GlideRecord.getRowCount()
When a server-side script only needs to know how many records match a condition, GlideRecord with getRowCount() is usually the wrong tool.
It works, but it is a record-oriented API solving an aggregate problem.
If your intent is “count matching rows,” say that directly with GlideAggregate and COUNT.
1. The common pattern
This is easy to find in background scripts, Business Rules, and Script Includes:
var gr = new GlideRecord("incident");
gr.addActiveQuery();
gr.addQuery("priority", 1);
gr.query();
var count = gr.getRowCount();
gs.info("Active P1 incidents: " + count);
The code is simple, but the intent is not “work with incident records.” The intent is “give me a count.”
That distinction matters because GlideRecord is built for reading rows. If all you need is the total, using a dedicated aggregate API is clearer and usually cheaper.
2. The better fit: GlideAggregate
Use GlideAggregate when the output is an aggregate such as COUNT.
var agg = new GlideAggregate("incident");
agg.addActiveQuery();
agg.addQuery("priority", 1);
agg.addAggregate("COUNT");
agg.query();
var count = 0;
if (agg.next()) {
count = parseInt(agg.getAggregate("COUNT"), 10);
}
gs.info("Active P1 incidents: " + count);
This version expresses the real requirement directly:
- target table:
incident - filter: active priority 1 records
- result: count
That is easier to read and easier to defend in a code review.
3. Why getRowCount() is the wrong default
The problem is not that getRowCount() is forbidden. The problem is using it as a counting strategy when counting is the whole job.
That usually leads to weaker code for three reasons:
- It communicates the wrong intent. A reader sees
GlideRecordand expects row processing, not aggregation. - It scales worse as data grows because the script is built around record retrieval rather than around an aggregate operation.
- It encourages copy-paste patterns where developers query a table first and only later realize they never needed the rows.
On a small instance the difference may look unimportant. On larger tables, frequent jobs, or shared utility code, these choices add up.
4. A useful nuance
If your script already needs to loop through the matching records for other reasons, then GlideRecord is still the right API.
For example:
var gr = new GlideRecord("sc_task");
gr.addActiveQuery();
gr.addQuery("assignment_group", groupSysId);
gr.query();
while (gr.next()) {
// real record processing happens here
}
In that kind of script, the main operation is processing rows, not getting a count. The count may be secondary.
The anti-pattern is this:
- run a
GlideRecordquery - do not use the records
- call
getRowCount() - stop
If that is the whole flow, use GlideAggregate.
5. If you only need to know whether a record exists
Counting is still too much work when the real question is only “does at least one record match?”
In that case, do not count at all. Ask for one row and stop.
var gr = new GlideRecord("incident");
gr.addActiveQuery();
gr.addQuery("caller_id", callerSysId);
gr.setLimit(1);
gr.query();
if (gr.next()) {
gs.info("Caller has at least one active incident.");
}
That pattern is usually better than both getRowCount() and GlideAggregate when you only need an existence check.
6. A practical rule of thumb
Use this split:
- need matching records:
GlideRecord - need only a count:
GlideAggregatewithCOUNT - need only existence:
GlideRecordwith a narrow query andsetLimit(1)
That keeps the API aligned with the job.
Final thought
Good ServiceNow code is not only about making something work. It is also about choosing the API that matches the real question.
If the question is “how many records match this filter?”, do not start with GlideRecord and then back into a count with getRowCount().
Start with GlideAggregate and make the intent explicit from the first line.