Question
Rick Prichett · May 3, 2021

Property defined as null or consisting of sub-properties

Needing to know how to define a property that can either be sent in my response as 

"members": null,

or 

"members": [
                {
                    "dob": "1905-05-01",
                    "firstName": "BOB",
                    "middleName": "T",
                    "nameSuffix": "",
                    "genderCode": "M",
                    "lastName": "COLLINS",
                    "memberId": "123421741",
                    "relationship": "Subscriber"
                }
            ],

Not sure if this is possible.  Currently defined as 

Property members As %VarString;

Product version: IRIS 2020.1
00
2 0 6 89
Log in or sign up to continue

Replies

Property members As  %DynamicObject;

Since the JSON content of 'members' property is a JSON array (aka the ObjectScript class %DynamicArray) and that array contains a list of JSON objects (aka the ObjectScript class %DynamicObject), I assume you don't really want a members array containing less that 1 element to be the null JSON value but instead you want that members value to be an empty array, I.e.

    set ObjectScriptObject.members=[ ]

Making this choice would mean ObjectScriptObject.members is always a %Dynamic.Array containing 0 or more elements.

A *property* of a class always contains an ObjectScript value that can be a string, a canonical decimal number, a $DOUBLE(...) IEEE 64-bit floating-point value or an oref.  An oref is a reference to a Class type object which includes the %DynamicArray and %DynamicObject classes.  The %DynamicArray/Object classes are special in that they can contain zero or more elements where each element can either be a JSON value or an ObjectScript value.  Where appropriate, conversions will be performed between JSON values and ObjectScript values.

ObjectScript variables and [MULTIDIMENSIONAL] properties can contain ObjectScript arrays of ObjectScript values.  These ObjectScript arrays are hierarchical, or tree like.  Internal and leaf elements can have a value or can be undefined.  A non-multidimensional property and an ObjectScript valued element in a %DynamicArray/Object object are not hierarchical and not undefined.  Non-multidimensional properties and elements that have not been initialized will have the empty string, "", as their value the first time they are accessed.

I am still getting "ERROR #9406: Unexpected format for value of field, members, using class base mapping".

Is there anything else that needs to be set along with the %DynamicArray?  I also tried %DynamicObject as well.

Property members As %DynamicArray; Property relationship As %String; Storage Default
{
<Data name="members">
<Attribute>members</Attribute>
<Structure>node</Structure>
<Subscript>"members"</Subscript>
</Data>

I assume (according to the error message you show) you are trying to import some JSON-formatted data into an IRIS class. In addition I recommend the reading of https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls...

To achieve this, you must define two IRIS classes:

Class DC.Rick.MemberData Extends (%Persistent, %JSON.Adaptor)
{
Property members As list Of Member;
}

Class DC.Rick.Member Extends (%SerialObject, %JSON.Adaptor)
{
Property dob As %Date;
Property firstName As %String;
Property middleName As %String;
Property nameSuffix As %String;
Property genderCode As %String;
Property lastName As %String;
Property memberId As %Integer;
Property relationship As %String;
}

Furthermore, I assume you have data like this (I shortened your example to keep things simple):

set memb0={"dob":"1990-07-18", "firstName":"Bob", "memberId":123956}
set memb1={"dob":"1990-05-25", "firstName":"Bill", "memberId":12345}
set memb2={"dob":"1990-10-30", "firstName":"Tommy", "memberId":4567}
set data(1)={"members":[(memb0)]}.%ToJSON()         // one member
set data(2)={"members":null}.%ToJSON()              // no member at all
set data(3)={"members":[(memb1),(memb2)]}.%ToJSON() // two members

check the examples:

for i=1:1:3 write data(i),!

the output should be:

{"members":[{"dob":"1990-07-18","firstName":"Bob","memberId":123956}]}
{"members":null}
{"members":[{"dob":"1990-05-25","firstName":"Bill","memberId":12345},{"dob":"1990-10-30","firstName":"Tommy","memberId":4567}]}

now import those data

for i=1:1:3 {
   set oref=##class(DC.Rick.MembersData).%New()
   if oref.%JSONImport(data(i)), oref.%Save() { write "OK",! } else { write "ERR",! }
}

If everything goes well, you should get three "OK"s and your data global looks like this

zwrite ^DC.Rick.MemberDataD
^DC.Rick.MemberDataD=3
^DC.Rick.MemberDataD(1)=$lb("",$lb($lb($lb(54620,"Bob","","","","",123956,""))))
^DC.Rick.MemberDataD(2)=$lb("","")
^DC.Rick.MemberDataD(3)=$lb("",$lb($lb($lb(54566,"Bill","","","","",12345,"")),$lb($lb(54724,"Tommy","","","","",4567,""))))

check member sizes:

for i=1:1:3 set oref=##class(DC.Rick.MemberData).%OpenId(i) write oref.members.Size,!

and the output should be:

1
0
2

I hope this is a good starting point for you...

Thanks for the response Julius.  I have used that before when the property came in the JSON consistently in the same format.  In this case it can come in as: 

"members": null,

or as:

"members": [
                {
                    "dob": "1905-05-01",
                    "firstName": "BOB",
                    "middleName": "T",
                    "nameSuffix": "",
                    "genderCode": "M",
                    "lastName": "COLLINS",
                    "memberId": "123421741",
                    "relationship": "Subscriber"
                }
            ],

Not sure this way will accommodate the two possible structures.

Both possible structures are considered. Here, I use the  examples from my previous posting:

set obj=##class(DC.Rick.MemberData).%OpenId(1)
do obj.%JSONExport() --> {"members":[{"dob":"1990-07-18","firstName":"Bob","memberId":123956}]}
set obj=##class(DC.Rick.MemberData).%OpenId(2)
do obj.%JSONExport() --> {}

The second example outputs {} only and not {"members":null}, I don't know why. Maybe there is a parameter which control this behavior, please ask WRC. 

From the view of data value, you can consider {} and {"members":null} as equal.

write {"members":null}.%GetTypeOf("members") --> null
write {}.%GetTypeOf("members") ----------------> unassigned

Both representation mean, the members property has no value. But, yes, but you can philosophize about it ...