How to count issues from a JQL search result in Groovy or REST API in Jira
Platform notice: Server and Data Center only. This article only applies to Atlassian products on the Server and Data Center platforms.
Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.
*Except Fisheye and Crucible
Summary
This article shares some best-practices on counting the number of issues returned by a JQL search in Jira through the REST API or native API (com.atlassian.jira.issue.search.SearchProvider or com.atlassian.jira.bc.issue.search.SearchService).
The Java or Groovy API is usually used through Groovy-enabling apps (link to the Marketplace search) in Workflow validations, conditions and post-functions and are often to check "if there are any results" matching the JQL or if they are above or under a certain threshold.
If this is your scenario, this article may interest you.
Environment
All versions of Jira Core 7.x and 8.x
Solution
Java or Groovy API
A method that's often used is the search()
from com.atlassian.jira.issue.search.SearchProvider
or com.atlassian.jira.bc.issue.search.SearchService
.
A caveat of this method is that it actually loads in memory the Index documents of all issues in the result — or it tries, if it doesn't cause the JVM to stall with Full GCs or OutOfMemoryError. The size of each issue index document depends on how many fields are populated (and configured in the Field Configuration) and their complexity — yet even if the average issue index document's small, running a too broad JQL may ask Jira to load all those millions of issues into the Heap.
If you're only interested in the issue count from such query, use the searchCount()
method instead:
public long searchCount (Query query, ApplicationUser searcher)
Return the number of issues matching the provided search criteria. Note: This does not load all results into memory and provides better performance than
search(com.atlassian.query.Query, User, com.atlassian.jira.web.bean.PagerFilter)
The excerpt above's from the searchProvider doc, but the same applies to the searchService
.
REST API
The REST API doesn't provide a native "count-only" endpoint or param, but you can optimize it's usage and lower response size and duration (and network traffic) by passing these two parameters to the /rest/api/2/search
endpoint:
<jira-base-url>/rest/api/2/search?fields=id&maxResults=0&jql=...
- fields: use either the "id" or "key" fields. Both these fields are always present in each issue so there's no additional overhead fetching or building them from the Index. It's good practice to always ask for only the fields you need, or else Jira will build the payload with every field present in the Field Configuration for that Project and Issue Type. (check out our Jira cleanup guide for tips on that!)
- maxResults: setting it to 0 forces an empty return, preventing overhead on building and transferring data. Passing 0 makes the
fields
param ineffective, but it's a good habit to always have thefields
in every/search
request.
The response output should be a HTTP 200 and it's content something like:
{"startAt":0,"maxResults":0,"total":23363,"issues":[]}
The trick is the "total" value is returned regardless of the maxResults
.
The REST API automatically paginates the results thus preventing loading the total
issues into memory at once, but the fields=id
and maxResults=0
parameters are optimizations and best-practices, anyway.