Question
· Jul 1

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 = $$$OK
  try{
  set tHTTPRequest = ##class(%Net.HttpRequest).%New()
  set tHTTPRequest.SSLConfiguration = ..Adapter.SSLConfig
  set tHTTPRequest.Https = 1
  set tHTTPRequest.WriteRawMode = 1
  set 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?

Product version: IRIS 2024.1
$ZV: IRIS for UNIX (Red Hat Enterprise Linux 8 for x86-64) 2024.1 (Build 267_2U) Tue Apr 30 2024 16:06:39 EDT [HealthConnect:7.2.0-1.r1]
Discussion (3)4
Log in or sign up to continue
	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/scopusauthor

P.S.: please note that, as posted, the json sample you provide is invalid.

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.