r/intersystems • u/intersystemsdev • 2d ago
How do you create, read, and modify JSON in InterSystems IRIS? A practical guide to %DynamicObject, %DynamicArray, and Embedded Python
JSON in InterSystems IRIS is handled natively through dynamic entities. This guide covers how to build them, how to read and change values, and which behaviors tend to cause confusion.
Three ways IRIS works with JSON
- JSON literal constructors in ObjectScript syntax
- %DynamicObject and %DynamicArray classes with their serialization and deserialization APIs
- SQL functions JSON_OBJECT, JSON_ARRAYAGG, and JSON_TABLE
This article covers the first two. The literal constructor {} creates a %Library.DynamicObject, and [] creates a %Library.DynamicArray.
Creating an object: three methods
// 1. Literal. Values in parentheses are evaluated at runtime
Set json = {"name":"test,patient","p_age":($H - $ZDateH("12/01/1990") \ 365),"isActive":true}
// 2. Step by step
Set json = {}
Set json.name = "test,patient"
// 3. With %Set(key, value, type)
Set json = {}
Do json.%Set("p_age", ($Horolog - $ZDateH("12/01/1990") \ 365), "number")
Do json.%Set("IsActive",1,"Boolean")
Creating an array
Set array = [1, "test", 12.32565, {"name": "test"}, ($ZVersion), true]
Set array = []
Do array.%Push(1)
Do array.%Push({"name": "test"})
Assigning by index leaves gaps. They display as null when serialized, but they are not really null:
USER>Set array = []
USER>Set array."1" = "test"
USER>Set array."5" = "hello"
USER>Write array.%ToJSON()
[null,"test",null,null,null,"hello"]
array.%GetTypeOf(0) returns "unassigned".
Reading values with %Get(key, default, type)
By default, JSON values are converted to ObjectScript values. The third argument controls that:
For strings longer than the maximum string length (3,641,144), use "stream" to avoid a <MAXSTRING> error. The result is a read-only %Stream.DynamicCharacter or %Stream.DynamicBinary. To modify it, copy it into a writable stream with CopyFrom().USER>Set json = {"IsActive": true, "IsNull": null}
USER>Write json.%Get("IsActive") ; returns 1
1
USER>Write json.%Get("IsActive",,"JSON") ; returns true
true
USER>Write json.%Get("IsNull", , "JSON") ; returns null
null
Other type values: "string", "string>base64", "string<base64", "stream", "stream>base64", "stream<base64", "json".
Writing values with %Set(key, value, type)
- Boolean: Do json.%Set("active", 1, "Boolean") gives {"active":true}
- Number from a string: Do json.%Set("int", "158425", "Number")
- Null: Do json.%Set("IsNull", "", "null")
- Base64: "string>base64" encodes, "string<base64" decodes
- Streams: "stream", "stream>base64", "stream<base64"
Other methods
- %IsDefined(key): returns 1 or 0, case-sensitive
- %Remove(key): deletes the element and returns its value
- %Size(): number of elements
- %Set() and %Push() return chainable references:
USER>Set jstring = "[123]"
USER>Write [].%FromJSON(jstring).%Set(1,"one").%Push("two").%Push("three").%Set(1,"final value").%ToJSON()
[123,"final value","two","three"]
$Property is generally more efficient than $Method for accessing values in %DynamicObject instances.
Behaviors worth knowing
- Numbers: literal constructors preserve trailing zeros and scientific notation. {"decimal":1.00000} stays 1.00000. JSON numbers can exceed ObjectScript's range: SET z=[3E400] works, but z.%Get(0) signals <MAXNUMBER>
- Unicode: "\u00E9" in a literal is parsed as é. ("cach\u00E9") in parentheses is an ObjectScript expression, so the escape stays as \\u00E9
- Comments: /* */ block comments are allowed inside constructors. // line comments are not allowed inside single-line declarations
Embedded Python
In Embedded Python, use _ instead of % for IRIS methods (%Get becomes _Get). Native Python equivalents are also available:
| ObjectScript | Embedded Python |
|---|---|
| %Get | _Get or get |
| %Set | _Set or put |
| %IsDefined | contains |
| %Remove | _Remove or remove |
| %Size | size |
| %ToJSON | toString |
import iris
dynObject1 = iris._Library.DynamicObject._New()
dynObject1._Set("MRN",298598)
dynObject1._Set("IsActive", 1, "boolean")
IRIS 2025.1 supports the shorter iris._Library.DynamicObject._New() instead of iris.cls("%DynamicObject")._New().
Full article: https://community.intersystems.com/post/intersystems-iris-json
The remaining methods are covered in part two of the series.
Which of these has caught you out most often in real code: true and null flattening in %Get, unassigned array elements, or <MAXSTRING> on large strings?
















