# Scripting Fundamentals Using Glide

> Chapter 8 of the Courseiva SERVICENOW-CAD curriculum — https://courseiva.com/learn/servicenow-cad/scripting-fundamentals-using-glotch

**Official objective:** 4.1 — Use GlideRecord, GlideAggregate, and GlideSystem for data operations

## Introduction

Exam objective 4.1 focuses on how to perform data operations in ServiceNow. This chapter covers Scripting Fundamentals Using Glide, which is the toolkit you use almost every time you write code in ServiceNow. For someone studying for the SNOW-CAD exam, understanding GlideRecord, GlideAggregate, and GlideSystem is essential because they are the building blocks for querying, creating, updating, and analysing data — the core tasks of any ServiceNow developer.

## The Personal Assistant Filing System Analogy

Have you ever had to find a specific piece of paper buried in a massive pile on your desk? You know it's there somewhere, but you have to dig through everything to find it. That's slow and frustrating, right?

Now imagine you have a personal assistant. You tell them, 'Get me the signed contract from the Smith account from last Tuesday.' Your assistant walks to a filing cabinet, opens the 'Clients' drawer, pulls the 'Smith' folder, finds the 'Contracts' section, checks the date for last Tuesday, and hands you the exact paper you need. You didn't need to know which drawer, which folder, or which section. You only needed to know what you wanted.

This is exactly how GlideRecord works. The 'filing cabinet' is the ServiceNow database. The 'drawers' and 'folders' are tables and records. The 'personal assistant' is GlideRecord — a set of pre-written code (a class) that does the searching and fetching for you. You just tell it what you want ('Get the user with the email john@example.com'), and it handles the complex back-end work of connecting to the database, running the search, and returning the result. Before GlideRecord, you would have had to write dozens of lines of complicated code just to ask for one record. Now, you write a few simple lines.

GlideAggregate is like asking your assistant for a summary: 'How many contracts did we sign this month?' GlideSystem is like asking your assistant about the office rules: 'What time does the office close today?' All three are tools that save you from doing the hard work yourself.

## Core explanation

At its heart, ServiceNow is a database that stores all your company's information — users, incidents, change requests, hardware assets, and much more. When you write scripts, you often need to talk to that database. This is where the three 'Glide' classes come in. A 'class' in programming is like a blueprint for creating objects that have specific properties and abilities. Each Glide class gives you a set of pre-built tools (methods and functions) to interact with the database in different ways.

**GlideRecord** is the most important and most commonly used tool. It lets you read, create, update, and delete records in the database. Think of a 'record' as a single row in a spreadsheet. For example, a user record has fields like 'First Name', 'Last Name', and 'Email'. GlideRecord lets you write code like: 'Find me all records in the User table where the Email is john@example.com'. It then returns those records, and you can loop through them one by one and do something with each.

Here is how GlideRecord works, step by step:

- First, you create a new GlideRecord object and tell it which table you want to work with. A 'table' is like a spreadsheet within the database (e.g., the 'Incident' table or the 'User' table).
- Then, you define your query conditions. A 'condition' is your filter — for example, 'priority equals 1' or 'category equals Hardware'.
- Next, you run the query. This tells ServiceNow to go to the database and fetch all records that match your conditions.
- Finally, you loop through the results. A 'loop' is a programming structure that repeats the same block of code for each record found.

Here is a simple example: Suppose you want to get all incidents with priority 1. Your code would look like this:

var gr = new GlideRecord('incident');
gr.addQuery('priority', 1);
gr.query();
while (gr.next()) {
  gs.print(gr.number + ' - ' + gr.short_description);
}

The 'gs' in the last line is short for 'GlideSystem', which we will discuss shortly. This script prints out the number and short description of every priority 1 incident in the system.

**GlideAggregate** is a specialised version of GlideRecord used for calculations — summing up numbers, counting records, finding averages, mins, and maxes. If GlideRecord is your personal assistant fetching individual papers, GlideAggregate is your assistant giving you a summary report. For instance, if you need to know how many incidents are currently open, you would use GlideAggregate with a 'COUNT' function. You do not need to loop through every incident; GlideAggregate does the math on the database side and returns just the number you need.

- GlideAggregate is useful for answering business questions like: 'What is the average time to resolve incidents this month?' or 'How many assets are assigned to each department?'
- It uses the same 'addQuery' method to filter records, but then you add 'addAggregate' with a function like 'COUNT', 'SUM', 'AVG', 'MIN', or 'MAX'.
- After running the query, you can get the result using 'getAggregate'.

**GlideSystem** (often abbreviated as 'gs') is your utility toolkit for everything related to the current session, the current user, the system date and time, logging messages, and more. It is like having a Swiss Army knife for script-wide tasks. When you write 'gs.print()', you are using GlideSystem to print a message to the system log. You can also get the current user's ID (gs.getUser()), the current date and time (gs.nowDateTime()), or generate a unique ID (gs.generateGUID()). You do not use GlideSystem to query the database — that is GlideRecord's job. GlideSystem handles the context of the script itself.

Why do these three tools exist? Before ServiceNow, developers would have to write raw Structured Query Language (SQL) queries to interact with databases. SQL is powerful but also dangerous because it can accidentally damage data if not written carefully. GlideRecord wraps that complexity in a safe, easy-to-use layer. It also ensures that ServiceNow's internal security rules (Access Control Lists, or ACLs) are respected. When you use GlideRecord, you automatically honour the permissions of the user running the script. If you used raw SQL, you might bypass those security checks.

In summary, GlideRecord is for reading and writing records. GlideAggregate is for calculations on groups of records. GlideSystem is for system-level utilities. Together, they form the foundation of nearly every script you will write in ServiceNow.

## Real-world context

An IT professional at a mid-size company is asked to build a script that sends a daily email to managers listing all high-priority incidents that have not been updated in the last 24 hours. Here is how they would use GlideRecord, GlideAggregate, and GlideSystem to solve this problem step by step.

First, the developer uses GlideRecord to find all incidents with priority 1 or 2. They write a query using 'addQuery' to filter only active incidents with a priority of 1 or 2. They also add a condition to check that the 'sys_updated_on' field (the date the record was last updated) is more than 24 hours ago. This is done using GlideRecord's special date query functions.

Next, the developer needs to group these incidents by the manager assigned to each incident. They could loop through all the results and manually build a list per manager, but that is inefficient. Instead, they use GlideAggregate with 'addAggregate('COUNT')' to count how many incidents are assigned to each manager, then filter to only those managers who have at least one high-priority incident that meets the time criteria. This gives them a summary without having to process every single incident record.

- The developer creates a GlideAggregate object on the 'incident' table.
- They add the same query conditions as before (priority 1 or 2, active, not updated in 24 hours).
- They use 'addAggregate('COUNT', 'assigned_to')' to count incidents per assigned user.
- They run the query and loop through the results to get each manager's sys_id and the count.

Now, the developer needs to send an email. They use GlideSystem to get the current time and format it nicely in the email. They also use GlideSystem's 'gs.getUser()' method to get the email address of each manager from the 'sys_user' table. They then use GlideRecord again to fetch the full manager record (their name, email, etc.) so they can personalise the email.

Finally, the developer uses GlideRecord to fetch the actual incident details (number, short description, state) for each manager, and they format those into the email body. They then use ServiceNow's email sending capabilities (which themselves use GlideRecord behind the scenes) to dispatch the emails. The entire script runs on a schedule, once a day, and the developer never writes a single line of SQL.

This workflow demonstrates the real-world synergy of the three Glide tools: GlideRecord for fetching detailed records, GlideAggregate for summary counts, and GlideSystem for session utilities like time formatting and user lookups. Without these tools, the developer would need to write a custom database connector and manage security themselves — a much more error-prone and time-consuming process.

## Exam focus

The SNOW-CAD exam tests objective 4.1 by asking you to identify the correct method, class, or syntax for a given data operation. The questions are typically multiple-choice, but they can also be drag-and-drop or true/false. Here is exactly what you need to know.

**GlideRecord is the most heavily tested Glide class.** Expect at least 3-4 questions on it. Key areas include:

- How to create a new GlideRecord object: new GlideRecord('table_name'). The table name must be the exact system name (often 'incident', 'task', 'sys_user'), not the display name.
- How to add a query condition: addQuery(field, operator, value). The 'operator' is optional — if you leave it out, it defaults to 'equals' ('').
- How to run the query: .query() method.
- How to iterate over results: .next() method inside a while loop.
- How to access field values: gr.field_name (where 'gr' is your GlideRecord variable).
- How to create a new record: .initialize() to create a blank record, then set field values with '=' and finally call .insert().
- How to update an existing record: use .setValue() to change fields, then call .update().
- How to delete a record: call .deleteRecord() on a single record.

**Traps to watch for:**

- A common trick is to ask which method returns multiple records. The answer is 'query()' — but some students confuse 'query()' with 'get()'. 'get()' returns a single record by sys_id and does not require a loop. 'query()' returns a set of records and requires a loop.
- Another trap: forgetting that 'addQuery' does not run the query by itself. You must call 'query()' afterwards.
- Some questions test whether you know that GlideRecord respects security rules by default. If the script runs as a user who lacks read access to a table, the query will return no records, even if the data exists.

**GlideAggregate is tested less frequently (1-2 questions), but the questions are direct.**

- You must know how to add an aggregate function: addAggregate('COUNT', 'field_name').
- You must know how to get the result after the query: getAggregate('COUNT', 'field_name').
- You must know that GlideAggregate extends GlideRecord, so it supports all the same query methods (addQuery, addOrderBy, etc.).
- Common exam question: 'Which class would you use to find the average number of days to close incidents?' Answer: GlideAggregate with 'AVG' aggregate.

**GlideSystem (gs) appears in almost every script example, but direct questions are rarer.**

- You will likely see one question asking which method provides the current date and time. The answer is gs.nowDateTime().
- Another question might ask how to log a message to the system log: gs.print() or gs.info(). Know that gs.print() is for debugging and gs.info() is for production logging.
- Know that 'gs.getUser()' returns a GlideRecord of the current user, not just a string. You then need to access fields like .getDisplayName() or .getEmail().

**Concepts you must memorise for the exam:**

- GlideRecord methods: new GlideRecord(), addQuery(), query(), next(), get(), setValue(), insert(), update(), deleteRecord().
- GlideAggregate methods: addAggregate(), getAggregate(), and all GlideRecord methods inherited.
- GlideSystem methods: nowDateTime(), getUser(), print(), info(), generateGUID().
- The difference between query() and get(): query() for multiple records, get() for a single record by sys_id.
- The difference between GlideRecord and GlideAggregate: for simple data access vs. calculations.

## Step by step

1. **Create a GlideRecord Object** — Start by creating a new GlideRecord instance and passing the table name as a string, e.g., new GlideRecord('incident'). This does not yet fetch any data — it just prepares a connection to that table.
2. **Define Query Conditions** — Use the addQuery() method to filter the records you want. For example, gr.addQuery('state', 1) filters for records where the state field equals 1 (which typically means 'new'). You can chain multiple addQuery calls to narrow down further.
3. **Execute the Query** — Call the .query() method on the GlideRecord object. This sends the query to the database and prepares the result set. No data is available yet until you start iterating.
4. **Loop Through Results** — Use a while loop with the .next() method to move through each returned record one by one. Inside the loop, you can access field values using dot notation, like gr.number or gr.short_description.
5. **Process or Modify Each Record** — Inside the loop, you can read field values, perform calculations, set new values (after which you call .update()), or even delete the record with .deleteRecord(). This is where you implement the business logic.
6. **Create a New Record (if needed)** — To add a new record, call .initialize() on a fresh GlideRecord object, set field values, then call .insert(). The sys_id of the new record is automatically generated.

## Comparisons

### GlideRecord vs GlideAggregate

**GlideRecord:**
- Used to fetch, create, update, and delete individual records
- Returns a set of records that you loop through with next()
- Cannot perform calculations like sum or average without custom code

**GlideAggregate:**
- Used to perform calculations on groups of records (count, sum, avg)
- Returns a single value or grouped results, not individual records
- Built-in methods like addAggregate() for calculations

### query() method vs get() method

**query() method:**
- Retrieves a set of records matching conditions
- Requires a loop (while next()) to access each record
- Does not require a sys_id; uses addQuery conditions

**get() method:**
- Retrieves a single record by its sys_id
- Does not require a loop; the record is directly accessible
- Requires the exact sys_id string as argument

### gs.print() vs gs.info()

**gs.print():**
- Designed for debugging; always writes to the log
- Not recommended for production scripts
- Outputs the message regardless of log level configuration

**gs.info():**
- Designed for production logging; respects log level settings
- Recommended for operational logging in live instances
- Output is controlled by the system log level, reducing noise

### Creating a New Record vs Updating an Existing Record

**Creating a New Record:**
- Use .initialize() to set up a blank record
- Set field values then call .insert() to save
- The sys_id is automatically generated

**Updating an Existing Record:**
- Use .get(sys_id) to fetch the existing record
- Use .setValue() or direct assignment to change fields
- Call .update() to save changes to the existing record

## Diagram

_Flowchart showing the process of using GlideRecord and GlideAggregate to query and process database records in ServiceNow._

```mermaid
flowchart TD
    A[Start Script] --> B[Create GlideRecord Object with Table Name]
    B --> C[Add Query Conditions with addQuery()]
    C --> D[Execute Query with .query()]
    D --> E{Records Found?}
    E -- Yes --> F[Loop with .next()]
    F --> G[Access Field Values or Modify]
    G --> H{More Records?}
    H -- Yes --> F
    H -- No --> I[End Script]
    E -- No --> I
    subgraph GlideAggregate
        C2[Add Aggregate Function with addAggregate()]
        D2[Execute Query]
        E2[Get Result with getAggregate()]
    end
    D --> C2
    C2 --> D2
    D2 --> E2
    E2 --> I
```

## Common misconceptions

- **Misconception:** You can use GlideRecord directly with the get() method to retrieve multiple records at once. **Reality:** get() is designed to retrieve a single record by its sys_id. To retrieve multiple records, you must use query() and then loop through the results with next(). (Beginners often think get() is a shortcut for 'getting' data, not realising it is specifically for a single record lookup.)
- **Misconception:** GlideRecord automatically returns all fields of a record when you loop through it, so you don't need to worry about performance. **Reality:** GlideRecord actually fetches all fields by default, but you can optimise performance by using addFields() to limit the fields returned, especially when dealing with large datasets. (The simplicity of GlideRecord hides the fact that it makes database calls, and fetching unnecessary fields can slow down the system. Beginners miss that performance matters.)
- **Misconception:** GlideAggregate is just a different name for GlideRecord and you can use them interchangeably. **Reality:** GlideAggregate is a subclass of GlideRecord specifically designed for aggregate functions like COUNT, SUM, AVG. You cannot use GlideRecord to calculate sums or averages directly without writing additional logic. (Because both classes share similar method names (like addQuery), beginners assume they are identical and wonder why one exists.)
- **Misconception:** You need to call .query() before calling .get() on a GlideRecord object. **Reality:** get() is a standalone method that does not require query() to be called first. It directly fetches a single record by its sys_id. Calling query() before get() will either have no effect or cause an error. (Students often see query() and get() as sequential steps, not realising they are two different ways to retrieve data.)
- **Misconception:** gs.print() is the best way to log errors in production scripts. **Reality:** gs.print() is intended for debugging only. In production scripts, use gs.info(), gs.warn(), or gs.error() so that log levels can be controlled and the system does not get flooded with debug messages. (gs.print() is easy to remember and type, so beginners default to it without understanding the logging hierarchy.)

## Key takeaways

- GlideRecord is the primary tool for reading, creating, updating, and deleting records in ServiceNow, and it automatically respects access control rules.
- Always call the .query() method after setting conditions with addQuery() to actually fetch records from the database.
- Use GlideAggregate when you need to perform calculations like count, sum, average, min, or max on a set of records.
- GlideSystem (gs) provides utility methods for session information, logging, dates, and user data — it is not used for database operations.
- The .get() method on a GlideRecord object retrieves a single record by sys_id and does not require a loop.
- GlideAggregate inherits all methods from GlideRecord, so you can filter records with addQuery() before applying aggregate functions.
- gs.print() is for debugging only; use gs.info() or gs.error() for production logging to avoid log bloat.
- When you create a new record with GlideRecord, you must call .initialize() before setting field values and .insert() to save it.

## FAQ

**What is the difference between GlideRecord and GlideAggregate?**

GlideRecord is used to retrieve and manipulate individual records. GlideAggregate is used to perform calculations like counting or summing across groups of records. GlideAggregate extends GlideRecord, so it has all the same methods plus aggregate-specific ones.

**Do I need to call .query() before .next()?**

Yes. .query() must be called first to execute the query. Then .next() moves through the result set. If you skip .query(), .next() will have no data to iterate over.

**Can I update a record without looping through all records?**

Yes, if you know the sys_id of the record, use .get(sys_id) to fetch it directly, then set new field values and call .update(). No loop is needed for single-record updates.

**Whats the difference between gs.print() and gs.info()?**

gs.print() is meant for debugging and sends output to the system log regardless of log level settings. gs.info() is for production logging and respects the log level configuration, making it more suitable for stable scripts.

**What does .initialize() do when creating a new record?**

It prepares the GlideRecord object to accept new data by setting default values and ensuring the object is ready for .insert(). Without .initialize(), the object may behave unexpectedly when setting fields.

**Can I use GlideRecord without learning SQL?**

Absolutely. GlideRecord abstracts SQL away completely. You only use method calls like addQuery() and next(). The database interactions happen behind the scenes, making it beginner-friendly.

## Check your understanding

1. **Which Glide class would you use to count the number of open incidents grouped by assignment group?**

   Answer: GlideAggregate, using addAggregate('COUNT', 'assignment_group') and then calling .query().

2. **What method must be called on a GlideRecord object to actually retrieve data after adding query conditions?**

   Answer: .query() must be called to execute the query and fetch the matching records.

3. **How do you retrieve a single incident record if you know its sys_id?**

   Answer: Use the .get(sys_id) method on a GlideRecord object, e.g., gr.get('abc123').

4. **What is the correct method to log a message for debugging in a development environment?**

   Answer: gs.print('your message') is used for debugging.

5. **Why should you avoid using gs.print() in a production script?**

   Answer: gs.print() logs messages regardless of the system log level, which can flood the log and degrade performance; use gs.info() instead.

---

Interactive version with quiz and diagrams: https://courseiva.com/learn/servicenow-cad/scripting-fundamentals-using-glotch
