Written by

Senior Sales Engineer at InterSystems Corporation
Question Theo Stolker · Dec 22, 2022

%DynamicObject: How to insert json property at a specific location?

Hi,

I know json does not impose any order, but for readability I would like to insert a json property at a specific location at the start of a %DynamicObject, not at the end.
Is there a known way to do that (other than string manipulation)?

Product version: IRIS 2022.1

Comments

Theo Stolker · Dec 22, 2022
/// Python reorder FHIR propertiesClassMethod PyFHIRResourceReOrder(resource As%String) As%String [ Language = python ]

{

    import json

    from collections import OrderedDict

    result = json.loads(resource, object_pairs_hook=OrderedDict)

    result.move_to_end("extension", last = False)

    result.move_to_end("meta", last = False)

    result.move_to_end("id", last = False)

    result.move_to_end("resourceType", last = False)

    return json.dumps(result)

}

This Python code is what I ended up with. It re-orders the properties "resourceType", "id", "meta" and "extension" to be at the start

0
Robert Cemper  Dec 22, 2022 to Theo Stolker

String manipulation under covers!  sad

0
Theo Stolker  Dec 22, 2022 to Robert Cemper

Yes, although the Python code does deal with an actual collection object :)

0
Julius Kavay · Dec 22, 2022

If you want to reorder JSON properties (alphabetically or just put some of them at the beginning) then use a utility method, like this, especially if you have several object(types) to reorder

Class DC.Utility Extends%RegisteredObject
{
/// Reorder a JSON Object or Array/// /// obj:  JSON-Object/// 	  ord: prop1, prop2, ...	Desired order for (some) properties/// 	       (Properties not listed are copied in the order in which they were created)/// 	       If ord not present, properties will be reordered in aplphabetical order/// 	       /// obj: JSON-Array/// 	 ord: pos1, pos2, ...	Desired order for (some) array items/// 	      (Items not listed are copied in ascending order)/// 	      ClassMethod ReOrder(obj As%DynamicAbstractObject, ord... As%String)
{
	i obj.%Extends("%DynamicObject") {
		snew={}, itr=obj.%GetIterator()
		i '$g(ord) {
			while itr.%GetNext(.k) { s done(k)=0 }
			sk="" f  sk=$o(done(k)) q:k=""dnew.%Set(k,obj.%Get(k))
		} else {
			f i=1:1:$g(ord) { sk=ord(i),done(k)=1d:$e(obj.%GetTypeOf(k),1,2)'="un"new.%Set(k,obj.%Get(k)) }
			while itr.%GetNext(.k,.v) { d:'$d(done(k)) new.%Set(k,v) }
		}
		
	} elseif obj.%Extends("%DynamicArray") {
		snew=[], itr=obj.%GetIterator(), max=obj.%Size(), done=""
		f i=1:1:$g(ord) { sk=ord(i) i k,k<=max dnew.%Push(obj.%Get(k-1)) s$bit(done,k)=1 }
		while itr.%GetNext(.k,.v) { d:'$bit(done,k+1) new.%Push(v) }
		
	} else { snew=obj }
	
	qnew
}
}

Some examples

s car={"color":"red", "fuel":"diesel", "maxspeed":150, "maker":"Audi", "model":"Quattro Q5", "power":300, "available":true, "rating":8, "allWheel":true }
s car1=##class(DC.Utility).ReOrder(car) // order all props alphabeticallys car2=##class(DC.Utility).ReOrder(car,"maker","model","available") // start with maker, model, etc.w car.%ToJSON(),!,car1.%ToJSON(),!,car2.%ToJSON() --->
{"color":"red","fuel":"diesel","maxspeed":150,"maker":"Audi","model":"Quattro Q5","power":300,"available":true,"rating":8,"allWheel":true}
{"allWheel":"1","available":"1","color":"red","fuel":"diesel","maker":"Audi","maxspeed":150,"model":"Quattro Q5","power":300,"rating":8}
{"maker":"Audi","model":"Quattro Q5","available":"1","color":"red","fuel":"diesel","maxspeed":150,"power":300,"rating":8,"allWheel":"1"}
0
Theo Stolker  Dec 27, 2022 to Julius Kavay

Thanks, Julius, that is really helpful!!

I have implemented the part of the method that I needed as follows:

/// Move FHIR resourceproperties in the followin order:/// - resourceType/// - id/// - meta/// - extensionClassMethod FHIROrderResourceProperties(resource As%DynamicObject) As%DynamicObject
{
    #dim order as%DynamicArray = [ "resourceType", "id", "meta", "extension" ]
    #dim newObject as%DynamicObject = {}

    for index = 0:1:order.%Size() - 1
    {
        set element = order.%Get(index)
        set done(element) = 1if$EXTRACT(resource.%GetTypeOf(element), 1, 2) '= "un"
        {
            do newObject.%Set(element, resource.%Get(element)) 
        }
    }
    
    set iterator = resource.%GetIterator()

    while iterator.%GetNext(.element, .value)
    {
        if '$DATA(done(element))
        {
            do newObject.%Set(element, value)
        }
    }

    return newObject
}

0