Iteration Help through JSON Response
I have built a REST operation to submit a JSON Request Body, and in the JSON Response Object, I need to pull out certain values like pureID, portalURL, and under the identifiers array the ClassifiedID that has a term."en_US" = "Scopus Author ID"
{
"count": 1,
"pageInformation": {
"offset": 0,
"size": 10
},
"items": [
{
"pureId": 0000000000000,
"uuid": "xxxxxxxxxxxxxxxxxxxxx",
"createdBy": "root",
"createdDate": "2024-11-18T22:01:07.853Z",
"modifiedBy": "root",
"modifiedDate": "2025-06-25T13:26:38.733Z",
"portalUrl": "https://xxxxxxxxxxxxxxxxxxxxx/en/persons/xxxxxxxxxx",
"prettyUrlIdentifiers": [
"samiksha-tarun"
],
"version": "506af93393c24eeb70826afa0dd0ed473f1b61cc",
"name": {
"firstName": "xxxxxxxxxx",
"lastName": "xxxxxxx"
},
"staffOrganizationAssociations": [
{
"typeDiscriminator": "StaffOrganizationAssociation",
"pureId": 1540250714,
"employmentType": {
"uri": "/dk/atira/pure/person/employmenttypes/academic",
"term": {
"en_US": "Academic"
}
},
"organization": {
"systemName": "Organization",
"uuid": "def8fdb5-6206-4bb7-99d6-b1efe8c60939"
},
"period": {
"startDate": "xxxx-xx-xx"
},
"primaryAssociation": false,
"contractType": {
"uri": "/dk/atira/pure/person/personcontracttype/openended",
"term": {
"en_US": "Open ended"
}
},
"staffType": {
"uri": "/dk/atira/pure/person/personstafftype/academic",
"term": {
"en_US": "Academic"
}
}
}
],
"selectedForProfileRefinementService": true,
"gender": {
"uri": "/dk/atira/pure/person/gender/unknown",
"term": {
"en_US": "Unknown"
}
},
"titles": [
{
"pureId": 1540250717,
"value": {
"en_US": "Assistant Professor"
},
"type": {
"uri": "/dk/atira/pure/person/titles/designation",
"term": {
"en_US": "Designation"
}
}
}
],
"visibility": {
"key": "FREE",
"description": {
"en_US": "Public - No restriction"
}
},
"identifiers": [
{
"typeDiscriminator": "PrimaryId",
"idSource": "synchronisedPerson",
"value": "xxxxxxxx"
},
{
"typeDiscriminator": "ClassifiedId",
"pureId": xxxxxxxxx,
"id": "xxxxxxxx",
"type": {
"uri": "/dk/atira/pure/person/personsources/employee",
"term": {
"en_US": "Employee ID"
}
}
},
{
"typeDiscriminator": "ClassifiedId",
"pureId": xxxxxxxx,
"id": "xxxxxxxx",
"type": {
"uri": "/dk/atira/pure/person/personsources/scopusauthor",
"term": {
"en_US": "Scopus Author ID"
}
}
}
],
"customDefinedFields": {},
"systemName": "Person"
}
]
}My REST Operation looks like...
Method PostSearchPerson(pRequest As osuwmc.COM.Request.SearchPerson, Output pResponse As osuwmc.COM.Response.StringResponse) As%Status
{
#dim tSC As%Status = $$$OKtry{
set tHTTPRequest = ##class(%Net.HttpRequest).%New()
set tHTTPRequest.SSLConfiguration = ..Adapter.SSLConfig
set tHTTPRequest.Https = 1set tHTTPRequest.WriteRawMode = 1set tHTTPRequest.Port = ..Adapter.HTTPPort
do tHTTPRequest.SetHeader("Host", ..Adapter.HTTPServer)
Do tHTTPRequest.SetHeader("Accept","application/json")
Do tHTTPRequest.SetHeader("Content-Type","application/json")
Do tHTTPRequest.SetHeader("api-key",..ApiKey)
do tHTTPRequest.EntityBody.Write()
do tHTTPRequest.OutputHeaders()
set tRequest = ##class(%DynamicObject).%New()
set tRequest.searchString = pRequest.searchString
set tPayload = tRequest.%ToJSON()
set tURL=..Adapter.URL
set tSC = tHTTPRequest.EntityBody.Write(tPayload)
set tHTTPResponse = ##class(%Net.HttpResponse).%New()
set tSC = ..Adapter.SendFormDataArray(.tHTTPResponse, "POST", tHTTPRequest, tURL, tPayload)
If$$$ISERR(tSC)&&$IsObject(tHTTPResponse)&&$IsObject(tHTTPResponse.Data)&&tHTTPResponse.Data.Size {
Set tSC=$$$ERROR($$$EnsErrGeneral,$$$StatusDisplayString(tSC)_":"_tHTTPResponse.Data.Read())
}
set tHttpResponseStatusCode = tHTTPResponse.StatusCode
set tHttpResponseStatusLine = tHTTPResponse.StatusLine
set tHttpResponseIsObject = $ISOBJECT(tHTTPResponse.Data)
Set tHttpResponseContentLength = tHTTPResponse.ContentLength
Set tHttpResponseContentInfo = tHTTPResponse.ContentInfo
Set tHttpResponseContentType = tHTTPResponse.ContentType
If ((tHttpResponseIsObject) && ($ZCONVERT(tHttpResponseContentType,"L") [ "application/json"))
{
set responseData = {}.%FromJSON(tHTTPResponse.Data)
set pResponse = ##class(osuwmc.COM.Response.StringResponse).%New()
if responseData.count =1{
set pResponse.COMPortalURL = responseData.items.%Get(0).portalUrl
set pResponse.COMPureID = responseData.items.%Get(0).pureId
set iterator = responseData.items.%GetAt(0).identifiers.%GetIterator()
while iterator.%GetNext(.key, .value) {
if responseData.items.%GetAt(0).identifiers.%GetAt(iterator).typeDiscriminator = "ClassifiedId"
{
if responseData.items.%GetAt(0).identifiers.%GetAt(iterator).type.term."en_US" = "Scopus Author ID" {
$$$LOGINFO(responseData.items.%GetAt(0).identifiers.%GetAt(iterator).value)
}
}
}
}
}
}
catch ex {
set tSC = ex.AsStatus()
}
quit tSC
}But when I execute I am getting...
| ERROR <Ens>ErrGeneral: Retrying Message body 9@osuwmc.COM.Request.SearchPerson / 3858480 because response 94@osuwmc.COM.Response.StringResponse / 121972 Status 'ERROR #5002: ObjectScript error: <METHOD DOES NOT EXIST>PostSearchPerson+37 ^osuwmc.COM.RESTOperation.1 *%GetAt,%Library.DynamicArray' |
If I take out
set iterator = responseData.items.%GetAt(0).identifiers.%GetIterator()
while iterator.%GetNext(.key, .value) {
if responseData.items.%GetAt(0).identifiers.%GetAt(iterator).typeDiscriminator = "ClassifiedId"
{
if responseData.items.%GetAt(0).identifiers.%GetAt(iterator).type.term."en_US" = "Scopus Author ID" {
$$$LOGINFO(responseData.items.%GetAt(0).identifiers.%GetAt(iterator).value)
}
}the code works fine...
I tried using Iterate over dynamic object | InterSystems Developer Community | Best
and got this...
Key: count
Type: number
Path: obj.count
Value: 1
Key: pageInformation
Type: object
Path: obj.pageInformation
Value:
Key: offset
Type: number
Path: obj.pageInformation.offset
Value: 0
Key: size
Type: number
Path: obj.pageInformation.size
Value: 10
Key: items
Type: array
Path: obj.items
Value:
Key: 0
Type: object
Path: obj.items.%GetAt(0)
Value:
Key: pureId
Type: number
Path: obj.items.%GetAt(0).pureId
Value: 1540250713
Key: uuid
Type: string
Path: obj.items.%GetAt(0).uuid
Value: 2a4f9baa-e937-4671-a55f-3f3bd17667d1
Key: createdBy
Type: string
Path: obj.items.%GetAt(0).createdBy
Value: root
Key: createdDate
Type: string
Path: obj.items.%GetAt(0).createdDate
Value: 2024-11-18T22:01:07.853Z
Key: modifiedBy
Type: string
Path: obj.items.%GetAt(0).modifiedBy
Value: root
Key: modifiedDate
Type: string
Path: obj.items.%GetAt(0).modifiedDate
Value: 2025-06-25T13:26:38.733Z
Key: portalUrl
Type: string
Path: obj.items.%GetAt(0).portalUrl
Value: https://xxxxxxxxxxxxxxxxxxx/en/persons/xxxxxxxxxxxxxxxxxxxx
Key: prettyUrlIdentifiers
Type: array
Path: obj.items.%GetAt(0).prettyUrlIdentifiers
Value:
Key: 0
Type: string
Path: obj.items.%GetAt(0).prettyUrlIdentifiers.%GetAt(0)
Value: xxxxxxxxxx
Key: version
Type: string
Path: obj.items.%GetAt(0).version
Value: 506af93393c24eeb70826afa0dd0ed473f1b61cc
Key: name
Type: object
Path: obj.items.%GetAt(0).name
Value:
Key: firstName
Type: string
Path: obj.items.%GetAt(0).name.firstName
Value: xxxxxxxx
Key: lastName
Type: string
Path: obj.items.%GetAt(0).name.lastName
Value: xxxxxxxxxxxx
Key: staffOrganizationAssociations
Type: array
Path: obj.items.%GetAt(0).staffOrganizationAssociations
Value:
Key: 0
Type: object
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0)
Value:
Key: typeDiscriminator
Type: string
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).typeDiscriminator
Value: StaffOrganizationAssociation
Key: pureId
Type: number
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).pureId
Value: xxxxxxxxxxxxx
Key: employmentType
Type: object
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).employmentType
Value:
Key: uri
Type: string
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).employmentType.uri
Value: /dk/atira/pure/person/employmenttypes/academic
Key: term
Type: object
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).employmentType.term
Value:
Key: en_US
Type: string
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).employmentType.term."en_US"
Value: Academic
Key: organization
Type: object
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).organization
Value:
Key: systemName
Type: string
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).organization.systemName
Value: Organization
Key: uuid
Type: string
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).organization.uuid
Value: xxxxxxxxxxxx
Key: period
Type: object
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).period
Value:
Key: startDate
Type: string
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).period.startDate
Value: xxxx-xx-xx
Key: primaryAssociation
Type: boolean
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).primaryAssociation
Value: 0
Key: contractType
Type: object
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).contractType
Value:
Key: uri
Type: string
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).contractType.uri
Value: /dk/atira/pure/person/personcontracttype/openended
Key: term
Type: object
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).contractType.term
Value:
Key: en_US
Type: string
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).contractType.term."en_US"
Value: Open ended
Key: staffType
Type: object
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).staffType
Value:
Key: uri
Type: string
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).staffType.uri
Value: /dk/atira/pure/person/personstafftype/academic
Key: term
Type: object
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).staffType.term
Value:
Key: en_US
Type: string
Path: obj.items.%GetAt(0).staffOrganizationAssociations.%GetAt(0).staffType.term."en_US"
Value: Academic
Key: selectedForProfileRefinementService
Type: boolean
Path: obj.items.%GetAt(0).selectedForProfileRefinementService
Value: 1
Key: gender
Type: object
Path: obj.items.%GetAt(0).gender
Value:
Key: uri
Type: string
Path: obj.items.%GetAt(0).gender.uri
Value: /dk/atira/pure/person/gender/unknown
Key: term
Type: object
Path: obj.items.%GetAt(0).gender.term
Value:
Key: en_US
Type: string
Path: obj.items.%GetAt(0).gender.term."en_US"
Value: Unknown
Key: titles
Type: array
Path: obj.items.%GetAt(0).titles
Value:
Key: 0
Type: object
Path: obj.items.%GetAt(0).titles.%GetAt(0)
Value:
Key: pureId
Type: number
Path: obj.items.%GetAt(0).titles.%GetAt(0).pureId
Value: xxxxxxx
Key: value
Type: object
Path: obj.items.%GetAt(0).titles.%GetAt(0).value
Value:
Key: en_US
Type: string
Path: obj.items.%GetAt(0).titles.%GetAt(0).value."en_US"
Value: Assistant Professor
Key: type
Type: object
Path: obj.items.%GetAt(0).titles.%GetAt(0).type
Value:
Key: uri
Type: string
Path: obj.items.%GetAt(0).titles.%GetAt(0).type.uri
Value: /dk/atira/pure/person/titles/designation
Key: term
Type: object
Path: obj.items.%GetAt(0).titles.%GetAt(0).type.term
Value:
Key: en_US
Type: string
Path: obj.items.%GetAt(0).titles.%GetAt(0).type.term."en_US"
Value: Designation
Key: visibility
Type: object
Path: obj.items.%GetAt(0).visibility
Value:
Key: key
Type: string
Path: obj.items.%GetAt(0).visibility.key
Value: FREE
Key: description
Type: object
Path: obj.items.%GetAt(0).visibility.description
Value:
Key: en_US
Type: string
Path: obj.items.%GetAt(0).visibility.description."en_US"
Value: Public - No restriction
Key: identifiers
Type: array
Path: obj.items.%GetAt(0).identifiers
Value:
Key: 0
Type: object
Path: obj.items.%GetAt(0).identifiers.%GetAt(0)
Value:
Key: typeDiscriminator
Type: string
Path: obj.items.%GetAt(0).identifiers.%GetAt(0).typeDiscriminator
Value: PrimaryId
Key: idSource
Type: string
Path: obj.items.%GetAt(0).identifiers.%GetAt(0).idSource
Value: synchronisedPerson
Key: value
Type: string
Path: obj.items.%GetAt(0).identifiers.%GetAt(0).value
Value: xxxxxx
Key: 1
Type: object
Path: obj.items.%GetAt(0).identifiers.%GetAt(1)
Value:
Key: typeDiscriminator
Type: string
Path: obj.items.%GetAt(0).identifiers.%GetAt(1).typeDiscriminator
Value: ClassifiedId
Key: pureId
Type: number
Path: obj.items.%GetAt(0).identifiers.%GetAt(1).pureId
Value: xxxxxx
Key: id
Type: string
Path: obj.items.%GetAt(0).identifiers.%GetAt(1).id
Value: xxxxxx
Key: type
Type: object
Path: obj.items.%GetAt(0).identifiers.%GetAt(1).type
Value:
Key: uri
Type: string
Path: obj.items.%GetAt(0).identifiers.%GetAt(1).type.uri
Value: /dk/atira/pure/person/personsources/employee
Key: term
Type: object
Path: obj.items.%GetAt(0).identifiers.%GetAt(1).type.term
Value:
Key: en_US
Type: string
Path: obj.items.%GetAt(0).identifiers.%GetAt(1).type.term."en_US"
Value: Employee ID
Key: 2
Type: object
Path: obj.items.%GetAt(0).identifiers.%GetAt(2)
Value:
Key: typeDiscriminator
Type: string
Path: obj.items.%GetAt(0).identifiers.%GetAt(2).typeDiscriminator
Value: ClassifiedId
Key: pureId
Type: number
Path: obj.items.%GetAt(0).identifiers.%GetAt(2).pureId
Value: xxxxxxx
Key: id
Type: string
Path: obj.items.%GetAt(0).identifiers.%GetAt(2).id
Value: xxxxxxx
Key: type
Type: object
Path: obj.items.%GetAt(0).identifiers.%GetAt(2).type
Value:
Key: uri
Type: string
Path: obj.items.%GetAt(0).identifiers.%GetAt(2).type.uri
Value: /dk/atira/pure/person/personsources/scopusauthor
Key: term
Type: object
Path: obj.items.%GetAt(0).identifiers.%GetAt(2).type.term
Value:
Key: en_US
Type: string
Path: obj.items.%GetAt(0).identifiers.%GetAt(2).type.term."en_US"
Value: Scopus Author ID
Key: customDefinedFields
Type: object
Path: obj.items.%GetAt(0).customDefinedFields
Value:
Key: systemName
Type: string
Path: obj.items.%GetAt(0).systemName
Value: Person
Can I get a second pair of eyes to take a look and see what I might be doing wrong? or give me a hint on how I could extract Scopus Author ID from identifiers.ClassifiedID?
Comments
Set json=##class(%DynamicAbstractObject).%FromJSONFile("c:\temp\scott.json")
Set itemIter=json.items.%GetIterator()
While itemIter.%GetNext(.key, .item) {
Set identifiersIter=item.identifiers.%GetIterator()
While identifiersIter.%GetNext(.key, .identifier) {
If (identifier.typeDiscriminator="ClassifiedId") && (identifier.type.term."en_US"="Scopus Author ID") {
Write"pureId: ",identifier.pureId,!
Write"uri: ",identifier.type.uri,!
}
}
}
Output:
pureId: xxxxxxxx
uri: /dk/atira/pure/person/personsources/scopusauthorP.S.: please note that, as posted, the json sample you provide is invalid.
Your error message says the %DynamicArray class does not have a %GetAt method. It has never had such a method although back in Caché 2016.1 there was an experimental array class that had a $getAt method.
You might try replacing all your .%GetAt(0) method calls with .%Get(0) method calls.
I am somewhat reluctant to show this as the performance is not great. We are working on that. Also, keep in mind that the expression language is JSON Path Language which was made an ISO Standard in the 2016 SQL Standard. We have extended it a bit and also implemented it in a way that allows it to be used outside of SQL which is not part of the Standard.
In this snippet, the lvar 'j' is assigned the value of the JSON posted by the OP. I modified it to make it valid JSON (just added quotes here and there).
do##class(%ASQ.SetUtils).pp(j.apply("$.items[*].identifiers[*]?(@.typeDiscriminator == 'ClassifiedId' && @.type.term.en_US == 'Scopus Author ID')"))The result:
[
{
"typeDiscriminator": "ClassifiedId",
"pureId": "xxxxxxxx",
"id": "xxxxxxxx",
"type": {
"uri": "/dk/atira/pure/person/personsources/scopusauthor",
"term": {
"en_US": "Scopus Author ID"
}
}
}
]The performance of apply() can be improved significantly by parsing the expression first and then passing the parsed result to apply(). For one-off executes that isn't helpful but if you are applying the same expression to different data then the improvement is significant.
LATEST:USER>set ast = ##class(%ASQ.Parser).parse("$.items[*].identifiers[*]?(@.typeDiscriminator == 'ClassifiedId' && @.type.term.en_US == 'Scopus Author ID')")
LATEST:USER>set result = j.apply(ast)
LATEST:USER>do##class(%ASQ.SetUtils).pp(result)
[
{
"typeDiscriminator": "ClassifiedId",
"pureId": "xxxxxxxx",
"id": "xxxxxxxx",
"type": {
"uri": "/dk/atira/pure/person/personsources/scopusauthor",
"term": {
"en_US": "Scopus Author ID"
}
}
}
]You can also do this in SQL but it is quite verbose. You have to map the JSON values to columns in the SELECT. I can provide an example if it would be helpful.