Tajson
(Adding page to Category:TOC because it contains a TOC.)
 
(16 intermediate revisions by 3 users not shown)
Line 1: Line 1:
'''TaJson''' is a declarative approach to receive, send, transform and store json messages, with setup and maintenance environment done in minutes
'''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 of TaJson here: https://blog.mdriven.net/introducing-mdriven-tajson/
You can find the original introduction to TaJson here: https://blog.mdriven.net/introducing-mdriven-tajson/


==== Creating Json from objects ====
=== Creating JSON from objects ===
Easiest is to use [[OCLOperators AsTaJson|AsTaJson]] to create a Json object graph using a viewmodel as a template.
It is easiest to use [[OCLOperators AsTaJson|AsTaJson]] to create a JSON object graph using a ViewModel as a template.


==== Creating objectsfrom Json ====
=== Creating objects from JSON ===
Given a Json object iterates attributes and associations - matching names in a VMClass-instance, and updates internal hierarchy of VMClass given first attribute as key
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 hierachy below.
The RootObject must be given to the VMClass. After that, the JSON object updates the hierarchy below.


To facilitate update we look for special things in the ViewModel:
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 name ViewModelColumn - Action must return created object - if action is not found we will look at type info and create object. '''Note!''' the AddNew action MUST add the object to the association.
# 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 object due to missing in input and merge mode is not in effect
# 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 a object - can be used in the _AddNew action to look up existing object
# 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
# 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 [[OCLOperators MergeTaJson|MergeTaJson]] and [[OCLOperators ApplyTaJson|ApplyTaJson]] they both return a string (large) with a log of the Merge/Apply -log.
When using [[OCLOperators MergeTaJson|MergeTaJson]] and [[OCLOperators ApplyTaJson|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.
[[File:2023-01-16 17h32 35.png|none|thumb|x]]
 
'''''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.
[[File:2021-07-22 11h40 11.png|none|thumb|128x128px]]'''''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 <code>RawJSon=true</code> will "raw" into the JSON result... make sure it is JSON!


==== Improving performance if updating an existing large dataset ====
==== 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.
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.
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 you add an action named <ViewModelColumn>'''_Lookup'''.  
For these special conditions, add an action named <ViewModelColumn>'''_Lookup'''.  


Looking at the image below, this is the explanation;
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''.
* 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 association.
* Use that variable as the expression of the many associations.
* Tajson will call the lookup action expecting it to fill the many association. There are many ways to do that, but here the expression will use oclPS to get client invoices.
* 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.
* 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 added to the list.
* 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|oclPS]] expression. See [[OCLOperators ExecutePS|ExecutePS]] for more information.
* vClientID is used to pass the key value to the [[OCLps|oclPS]] expression. See [[OCLOperators ExecutePS|ExecutePS]] for more information.
* When the action is done, Tajson proceeds as normal.
* When the action is done, Tajson proceeds as normal.
Please note that using this feature with [[OCLOperators ApplyTaJson|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.
Please note that using this feature with [[OCLOperators ApplyTaJson|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.
[[File:Lookup example.png|none|thumb|859x859px]]
[[File:Lookup example.png|none|thumb|859x859px]]


==== Special consideration for very large and deep Json structures  ====
=== 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.
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.


Especially the resolve and set of single links may prove problematic to do for a large number of leaf nodes in a large structure.
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).
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.
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:
=== Example: ===
 
Consider this JSON:
Consider this Json:
<pre>
<pre>
{
{
Line 73: Line 85:
We want to read this into a model like this:
We want to read this into a model like this:
[[File:2019-09-09 21h52 15.png|none|thumb]]
[[File:2019-09-09 21h52 15.png|none|thumb]]
For this we can use ApplyTaJSon with a ViewModel that looks like this:
For this, we can use ApplyTaJSon with a ViewModel that looks like this:
[[File:2019-09-09 21h54 01.png|none|thumb]]
[[File:2019-09-09 21h54 01.png|none|thumb]]
If we sometimes get a Json data structure with a 1000 Detail objects and each Detail object has 1000 Deep1 objects and each Deep1 had 1000 Deep2 objects - this would force ApplyTaJson to manage 1000*1000*1000 objects at once and that will not work.
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.
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:
To handle this, we make use of the RawJSon attribute in a new ViewModel like this:
[[File:2019-09-09 21h59 55.png|none|thumb]]
[[File:2019-09-09 21h59 55.png|none|thumb]]
If we now import with ViewOneThing_SemiDeep we get a result that looks like this (when we read it back with AsTajson):
If we now import with ViewOneThing_SemiDeep, we get a result that looks like this (when we read it back with AsTajson):
<pre>
<pre>
{
{
Line 95: Line 107:
</pre>
</pre>


We can now - in a separate pass - loop through a chunk of "Detail"-objects that has 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. And this is a much better way to handle the case of large datasets that could result in billions like 1000*1000*1000.
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]].
[[Category:JSON]]
{{Edited|July|12|2024}}


Read more on usage in [[Rest Services In MDriven]]
[[Category:TOC]]

Latest revision as of 14:14, 26 March 2024

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:

  1. 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.
  2. 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.
  3. 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
  4. 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.

x

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.

2021-07-22 11h40 11.png

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.

Lookup example.png

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:

2019-09-09 21h52 15.png

For this, we can use ApplyTaJSon with a ViewModel that looks like this:

2019-09-09 21h54 01.png

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:

2019-09-09 21h59 55.png

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.

This page was edited 53 days ago on 03/26/2024. What links here