| name | gliderecord-patterns |
| description | Write efficient ServiceNow GlideRecord queries โ addQuery vs addEncodedQuery, setLimit, GlideAggregate for counts, avoiding N+1 in loops, query operators, and safe CRUD with workflow control. |
| version | 1.0.0 |
| tools | ["snow_query_table","snow_execute_script","snow_discover_table_fields"] |
GlideRecord Best Practices for ServiceNow
GlideRecord is the primary API for database operations in ServiceNow. Following these patterns ensures efficient and secure queries.
Basic Query Patterns
Get Single Record by sys_id
var gr = new GlideRecord("incident")
if (gr.get("sys_id_here")) {
gs.info("Found: " + gr.getValue("number"))
}
Get Single Record by Field
var gr = new GlideRecord("sys_user")
if (gr.get("user_name", "admin")) {
gs.info("Found user: " + gr.getValue("name"))
}
Query Multiple Records
var gr = new GlideRecord("incident")
gr.addQuery("active", true)
gr.addQuery("priority", "1")
gr.orderByDesc("sys_created_on")
gr.setLimit(100)
gr.query()
while (gr.next()) {
gs.info(gr.getValue("number"))
}
Encoded Queries (Faster)
Use encoded queries for complex conditions - they're more efficient than multiple addQuery calls:
var gr = new GlideRecord("incident")
gr.addEncodedQuery("active=true^priority=1^assigned_toISEMPTY")
gr.query()
while (gr.next()) {
}
Performance Tips
1. Always Use setLimit()
var gr = new GlideRecord("incident")
gr.addQuery("active", true)
gr.setLimit(10)
gr.query()
2. Use getValue() for Strings
var number = gr.getValue("number")
var element = gr.number
var numberStr = gr.number.toString()
3. Use getDisplayValue() for References
var assignedToName = gr.getDisplayValue("assigned_to")
var assignedToId = gr.getValue("assigned_to")
4. Avoid Queries in Loops
for (var i = 0; i < userIds.length; i++) {
var gr = new GlideRecord("sys_user")
gr.get(userIds[i])
}
var gr = new GlideRecord("sys_user")
gr.addQuery("sys_id", "IN", userIds.join(","))
gr.query()
while (gr.next()) {
}
5. Use GlideAggregate for Counts
var count = 0
var gr = new GlideRecord("incident")
gr.addQuery("active", true)
gr.query()
while (gr.next()) {
count++
}
var ga = new GlideAggregate("incident")
ga.addQuery("active", true)
ga.addAggregate("COUNT")
ga.query()
if (ga.next()) {
var count = ga.getAggregate("COUNT")
}
CRUD Operations
Insert
var gr = new GlideRecord("incident")
gr.initialize()
gr.setValue("short_description", "New incident")
gr.setValue("caller_id", gs.getUserID())
gr.setValue("priority", "3")
var sysId = gr.insert()
Update
var gr = new GlideRecord("incident")
if (gr.get("sys_id_here")) {
gr.setValue("state", "6")
gr.setValue("close_notes", "Issue fixed")
gr.update()
}
Delete (Use with Caution!)
var gr = new GlideRecord("incident")
if (gr.get("sys_id_here")) {
gr.deleteRecord()
}
Bulk Update
var gr = new GlideRecord("incident")
gr.addQuery("state", "6")
gr.addQuery("resolved_at", "<", gs.daysAgoStart(30))
gr.query()
while (gr.next()) {
gr.setValue("state", "7")
gr.update()
}
Query Operators
| Operator | Example | Description |
|---|
= | addQuery('active', true) | Equals |
!= | addQuery('active', '!=', true) | Not equals |
>, < | addQuery('priority', '<', '3') | Greater/Less than |
>=, <= | addQuery('sys_created_on', '>=', gs.daysAgoStart(7)) | Greater/Less or equal |
CONTAINS | addQuery('short_description', 'CONTAINS', 'error') | Contains string |
STARTSWITH | addQuery('number', 'STARTSWITH', 'INC') | Starts with |
ENDSWITH | addQuery('email', 'ENDSWITH', '@company.com') | Ends with |
IN | addQuery('state', 'IN', '1,2,3') | In list |
NOT IN | addQuery('state', 'NOT IN', '6,7') | Not in list |
ISEMPTY | addQuery('assigned_to', 'ISEMPTY', '') | Field is empty |
ISNOTEMPTY | addQuery('assigned_to', 'ISNOTEMPTY', '') | Field is not empty |
Security Considerations
- setWorkflow(false) - Skip business rules for bulk operations
- setLimit() - Prevent runaway queries
- Check canRead()/canWrite() - Verify ACL permissions
- Never trust user input - Validate before using in queries