Practical ObjectScript Coding: From JSON to Globals to SQL
While starting with Intersystems IRIS or Cache, developers often encounter three core concepts: Dynamic Objects, Globals & Relational Table. Each has its role in building scalable and maintainable solutions. In this article, we'll walk through practical code examples, highlight best practices, and show how these concepts tie together.
1. Working with Dynamic Objects:
Dynamic objects (%DynamicObject and %DynamicArray) allow developers to manipulate JSON-like structures directly in Objectscript. They are especially useful for modern applications that need to parse, transform or generate JSON.
Example: Creating & Manipulating Dynamic Objects
// Create a Dynamic objectSet obj - {}
// Add propertiesSet obj.name = "Vachan"Set obj.age = 25// Nested objectsSet obj.address = {"city":"Bengaluru", "zip":"560000"}
// Add an ArraySet obj.skills = ["Objectscript", "SQL"]
// Convert to JSON stringSet json = obj.%ToJSON()
Write json,!
// Parse JSON string back to an objectSet parser = {}.%FromJSON(json)
Write parser.nameBest Practices:
- Always validate JSON input with %FromJSON() to catch errors.
- Use obj.%Get("property") when unsure if a property exists.
- Favor %DynamicArray for list-like structures.
2. Using Globals Effectively:
Globals are hierarchical sparse arrays stored directly in the IRIS database engine. They are extremely fast and can store virtually any structure.
Example: Storing Data in Globals
// Store student data in a globalSET^Student(1,"Name") = "Alice"SET^Student(1,"Age") = 29SET^Student(2,"Name") = "Bob"SET^Student(2,"Age") = 34// Retrieve dataWRITE^Student(1,"Name") // outputs: Alice// Iterate over all studentsSET id=""FORSET id=$ORDER(^Student(id)) QUIT:id="" {
WRITE"Student ",id,": ",^Student(id,"Name")," (Age ",^Student(id,"Age"),")",!
}Best Practices:
- Define a clear global structure before coding (avoid ad-hoc keys).
- Use globals for high-performance storage when SQL overhead is not needed.
- For application data, prefer persistent classes with globals managed under the hood.
3. Creating Relational SQL tables:
In IRIS, relational tables can be created using both SQL DDL and persistent classes.
Example: Creating a SQL Table via DDL
CREATETABLE Employee (
IDSERIAL PRIMARY KEY,
NameVARCHAR(50),
Age INT,
Department VARCHAR(50)
);Example: Creating the same table as a Persistent Class
Class Company.Employee Extends (%Persistent) {
Property Name As%String(MAXLEN=50);Property Age As%Integer;Property Department As%String(MAXLEN=50);
}Once compiled, this class automatically creates an underlying global and an SQL table. You can now use both ObjectScript and SQL:
// Create and save an employeeSET emp = ##class(Company.Employee).%New()
SET emp.Name = "Charlie"SET emp.Age = 40SET emp.Department = "IT"DO emp.%Save()
// Query employees with SQL
&sql(SELECTName, Age FROM Company.Employee)
WHILE (SQLCODE=0) {
WRITE"Employee: ",Name,", Age: ",Age,!
FETCH NEXT
}Best Practices:
- Prefer persistent classes for maintainable applications.
- Use SQL DDL for quick table definitions or integration with external systems.
- Always define indexes for commonly queried properties.
SUMMARY:
Whether you are parsing JSON payloads, managing high-speed lookup data, or designing relational tables, understanding when to use dynamic objects, globals, or persistent classes is key to becoming an effective ObjectScript developer.
Comments
instead of having each property stored with its name as a subscript, (e.g. ^Student(1,"Name") = "Alice" / ^Student(1,"Age") = 29 etc.)
its much better to use the same format the class compiler is storing data on the D global:
^Student(1)=$LB("Alice",29 ... )
when having globals with millions (or billions) of records it will have a huge impact on performance and storage footprint.
Instead of using obj.%Get("property"), you can use %IsDefined("key"), which returns 1 if the key exists.
You can also use %Get("key",, "type"), where the optional type parameter specifies the expected return type. This helps prevent <MAXSTRING> errors when handling values near IRIS's maximum string length.
To enable native JSON support in a persistent class, extend %JSON.Adaptor. This provides built-in methods such as:
%JSONImport()— Imports a JSON or DAO directly into the object.%JSONExport()— Export and display the value in the device%JSONExportToString()— Export the value as a string.%JSONExportToStream()— Export the value as a stream
Class Company.Employee Extends (%Persistent,%JSON.Adaptor) {
Property Name As%String(MAXLEN=50);Property Age As%Integer;Property Department As%String(MAXLEN=50);ClassMethod LoadData() As%Staus
{
Set json = {"Name":"Test", "Age": 20, "Department": "IT"}
Set obj = ..%New()
Set sc = obj.%JSONImport(json)
Set sc = obj.%Save()
Return sc
}
ClassMethod ExportDataAsJSONString(Id) As%String
{
Set obj = ..%OpenId(Id)
Do obj.%JSONExportToString(.string)
Return string
}
ClassMethod ExportDataAsJSONStream(Id) As%Steam.Object
{
Set obj = ..%OpenId(Id)
Do obj.%JSONExportToStream(.stream)
Return stream
}
}If you're working with classes, it's recommended to use object-based or SQL-based data manipulation rather than directly using globals.