TaJson is a declarative approach to receive, send, transform, and store JSON messages, with setup and maintenance environment done in minutes.
You can find the original introduction to TaJson here: https://blog.mdriven.net/introducing-mdriven-tajson/
Creating JSON from objects
It is easiest to use AsTaJson to create a JSON object graph using a ViewModel as a template.
Creating objects from JSON
Given that a JSON object iterates attributes and associations - matching names in a VMClass-instance, and updates the internal hierarchy of VMClass given the first attribute as key:
The RootObject must be given to the VMClass. After that, the JSON object updates the hierarchy below.
To facilitate the update, we look for special things in the ViewModel:
- Action <ViewModelColumn>_AddNew will be used to create new objects needed for ViewModel-association with the name ViewModelColumn. Action must return a created object - if action is not found, we will look at type info and create an object. Note! the AddNew action MUST add the object to the association.
- Action Delete in nesting will be used if found when we need to delete an object due to missing input and if merge mode is not in effect.
- Variable vImportKey:string if found will be updated prior to creating an object - can be used in the _AddNew action to look up an existing object
- Action CleanUpAction if found on root ViewModelClass (as a Column prepared for action in ViewModel Editor) will be called after the import is finished
When using MergeTaJson and ApplyTaJson, they both return a string (large) with a log of the Merge/Apply -log.
Tagged values to change the output
You can set the following tagged values to true on a multi-nesting column on the ViewModel in order to influence output.
TaJsonTreatListAsDynamicProperties. When this is true, we read the nesting in the ViewModel object and look for Name and Value properties. We then use the result as properties on the resulting JSON object. This enables you to create JSON with the definition given in runtime. When properties in Json are not matched with ViewModel columns on the same level, we check for a ViewModel multilink nesting that has the tagged value TaJsonTreatListAsDynamicProperties==true. If found, we turn all the unmatched JSON attributes into Name+Value pairs and send them to the ViewModel multilink. If this nesting has ViewModel columns Name and Value (strings), you get the names and values for properties you did not know in design time.
TaJsonTreatListAsValues. When this is true, we generate a JSON array of the first column in the ViewModel nesting. This gives a JSON array of values rather than objects.
RawJSon=true
When using AsTajson, you may want to inject snippets of already formatted JSON into the tree. If we do it as a string, we get quotations - and miss the point.
The introduced new tagged value RawJSon=true
will "raw" into the JSON result... make sure it is JSON!
Improving performance if updating an existing large dataset
When updating using the default behavior, Tajson will load all objects in the many associations to be able to look them up based on IDs in the JSON structure.
But, what if you have millions of objects? That will make updating very slow and might make your server run out of memory.
For these special conditions, add an action named <ViewModelColumn>_Lookup.
Looking at the image below, this is the explanation:
- A variable holding a collection of the objects you want to update. Here called vclient_invoices.
- Use that variable as the expression of the many associations.
- Tajson will call the lookup action expecting it to fill the many associations. There are many ways to do that, but here the expression will use oclPS to get client invoices.
- When Tajson calls the lookup action, vImportKey will contain a comma-separated list of the keys from the JSON.
- In the example, the oclPS is called for each key, and the resulting object is added to the list.
- vClientID is used to pass the key value to the oclPS expression. See ExecutePS for more information.
- When the action is done, Tajson proceeds as normal.
Please note that using this feature with ApplyTaJson needs special consideration. ApplyTaJson removes objects from the existing database not found in the JSON. To use this feature, the objects need to be present in the list you provide.
Special consideration for very large and deep JSON structures
When confronted with very large and deep JSON structures, it may be a good idea to split the processing and object creation into multiple smaller parts.
The resolve and set of single links may prove especially problematic for a large number of leaf nodes in a large structure.
To facilitate such splitting of large work into smaller pieces, we now allow for a special attribute in TaJSon import (Merge and Apply) - the special attribute is RawJSon:string (case sensitive).
When the logic finds a ViewModelColumn named RawJSon in a ViewModel nesting, the current JSON text is inserted as a string - this is the JSON for the current level and below.
Example:
Consider this JSON:
{ "SomeString": "Hello", "Details": [ { "Attribute1": "1111", "Attribute2": "222222", "Deep1": [ { "asString": "Deep1", "Attribute1": "1111", "Deep2": [ { "asString": "Deep2", "Attribute1": "222" } ] } ] } ] }
We want to read this into a model like this:
For this, we can use ApplyTaJSon with a ViewModel that looks like this:
If we sometimes get a JSON data structure with 1000 Detail objects and each Detail object has 1000 Deep1 objects and each Deep1 has 1000 Deep2 objects, this would force ApplyTaJson to manage 1000*1000*1000 objects at once and that will not work.
But the first level of only 1000 will not be a problem.
To handle this, we make use of the RawJSon attribute in a new ViewModel like this:
If we now import with ViewOneThing_SemiDeep, we get a result that looks like this (when we read it back with AsTajson):
{ "SomeString": "Helloxxx", "Details": [ { "Attribute1": "1111", "Attribute2": "222222", "RawJSon": "{\r\n \"Attribute1\": \"1111\",\r\n \"Attribute2\": \"222222\",\r\n \"Deep1\": [\r\n {\r\n \"asString\": \"Deep1\",\r\n \"Attribute1\": \"1111\",\r\n \"Deep2\": [\r\n {\r\n \"asString\": \"Deep2\",\r\n \"Attribute1\": \"222\"\r\n }\r\n ]\r\n }\r\n ]\r\n}" } ] }
We can now - in a separate pass - loop through a chunk of "Detail"-objects that have a JSON data structure in its Attribute3 and run ApplyTajson with this snippet of JSON and a new ViewModel to do things from here and downwards. This will give a worker like the MDrivenServer ServerSideJobs plenty of small pieces to work on over an extended time, one by one. This is a much better way to handle the case of large datasets that could result in billions like 1000*1000*1000.
Gotchas and common mistakes
When adding attributes to multi-nestings, the framework sets "true" in ReadOnly. This is because UI grid cells most often should be read-only, but readonly=true in TajSon really means ReadOnly even for import.
- Check that your ReadOnly settings are as you intended.
Read more on usage in Rest Services In MDriven.