%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
/// Python reorder FHIR properties ClassMethod 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
String manipulation under covers!
Yes, although the Python code does deal with an actual collection object :)
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") { s new={}, itr=obj.%GetIterator() i '$g(ord) { while itr.%GetNext(.k) { s done(k)=0 } s k="" f s k=$o(done(k)) q:k="" d new.%Set(k,obj.%Get(k)) } else { f i=1:1:$g(ord) { s k=ord(i),done(k)=1 d:$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") { s new=[], itr=obj.%GetIterator(), max=obj.%Size(), done="" f i=1:1:$g(ord) { s k=ord(i) i k,k<=max d new.%Push(obj.%Get(k-1)) s $bit(done,k)=1 } while itr.%GetNext(.k,.v) { d:'$bit(done,k+1) new.%Push(v) } } else { s new=obj } q new } }
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 alphabetically s 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"}
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 /// - extension ClassMethod 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) = 1 if $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 }