JS: Pushing a new object into nested array-objects

I realise my problem is about understanding JS objects and arrays, I thus published this request in stackoverflow, but either I did not explain my problem correctly, or people do not understand why I need to have nested arrays and objects in Node-RED global context. No-one came back to offer real help, accept a person that thinks I should be making all nested arrays objects as well. for searching of the objects, I think they should still be arrays, I still do not have a solution. Here is what I have published in Stackoverflow here


I want to build a nested JS object, with an array, objects, arrays, etc, that will keep homie variables at different levels, closely resembling an easy storage structure to store and retrieve from the homie v3.0.1 convention. (I include some of my own structures into the JS objects & arrays, to improve readiblity & flexibility of the code, like grouping variables leading with an _ underscore, so its not the same as the homie convention.)

The structure of the nested array / objects to be stored (in Node-RED global context - in JS object format), which I call the homie Shadow, (roughly deviceID > nodeID > propertyID > propAttribute, where devices, nodes, properties are all arrays of nested objects), are:

[
  {"deviceID":
    {"_nodesArr":
        [
          {"nodeID":{
              "_propArr":
                [
                  {"propertyID":{"_propertyAttributes":
                    {"$attribute: attributeValue}}}
  }  }    ]  }  }  ]
]

Below is an example dataset, which is stored in Node-RED in a global context variable called homieShw (short for homie Shadow):

[
  {"ESP70":
      {"_nodesArr":
        [
          {"Light": {
              "_propArr":
              [
                {"Switch":{
                          "val":1,
                          "_propAttributes":{"$settable":true}
  }  }    ]  }  }  ]
]

Now, heading to what I want to do, and my problem: The Javascript code, will receive messages from mqtt, to setup the above structure, but also update the variables, for instance, when the light of this ESP is switched off, the mqtt message looks as follows:

homie/ESP70/Light/Switch/1

Without needing to quote all the code I do, I have a specific problem - and that is to store into an array further down in the array hierarchy of the homie Shadow or variable arrHomieShw (retreived from the global context variable homieShw).

  • To add an ESP device in the object's first array, the JS code, which tests if the deviceID is in the array already, and if not, adds a new element to the array (this code works perfectly), from the incoming mqtt message above:

    function checkDeviceArrCreated(deviceID, arrHomieShw){
    
        for (i=0; i < arrHomieShw.length; i++) {
            if(deviceID !== Object.keys(arrHomieShw[i])[0] ) {
                foundDeviceID = 0 } else { foundDeviceID = 1; break }
        }
        if(foundDeviceID === 0){  
            branch = {[deviceID]:{ "_deviceAttributes": {  "$homie": $homie  } }};
            arrHomieShw.push( branch );
        }
    }
    
  • The above function checks if the object exits, and if it does not, it pushes the new branch into arrHomieShw, this works perfectly.

  • But now, I want to do same for the array at the next level of the hierarchy of homieShw. Thus, I want to write into the node array of objects, by checking if the nodeID exist for the deviceID, and if not, to push a new branch into it.

  • The push command does not want to push into a hierarchy as explained above. This is what I have tried, (amongst others). The function checkNodesArrCreated() is called, with for instance with this mqtt message : homie/ESP70/Air/Temperature/23, after the variable arrIdxDevice = getDeviceIdx(); - see this function also below.

  • In the function checkNodesArrCreated(), the branch variable - which is pushed into the nested array arrHomieShw creates a new object, and does not branch below the same deviceID it found. I also tried to use variations of arrHomieShw.deviceID.push( branch ), but this also does not work.

How should I go about this?

//-----------------------------------------------------------------------
function checkNodesArrCreated(){
    if(deviceID == Object.keys(arrHomieShw[arrIdxDevice])[0] ) {
        theObj = Object.values(arrHomieShw[arrIdxDevice][deviceID])
        if(theObj._nodesArr === undefined){
            branch = { _nodesArr:
                          {[nodeID]:{"_nodeAttributes": {  [nodeAttribute]: val  } } }
                      };
            arrHomieShw.push( branch );
        }
    }
}

//-----------------------------------------------------------------------
function getDeviceIdx(){
    for (i=0; i < arrHomieShw.length; i++) {
        if(deviceID == Object.keys(arrHomieShw[i])[0] ) {
            return i;
        }
    }
    return arrIdxDevice;
}

function getNodeIdx(deviceID, nodeID, arrIdxDevice, arrHomieShw){
    for (j=0; j < arrHomieShw[arrIdxDevice][deviceID]._nodesArr.length; j++) {
        if(nodeID == arrHomieShw[arrIdxDevice][deviceID]._nodesArr[j]){
            return j;
        }
    }
}

Could anybody help me out of the sink-hole I find myself in now?

Of course you might have a valid reason I'm unaware of, but it seems to me that if every Device has a unique DeviceID, every node within a device has a unique nodeID and every prop in a node has a unique property ID and then each attribute within is unique as well, then you could do without the arrays and it would be much simpler ...

{
"deviceID1": {
    "nodeID1": {
      "propertyID1": {
        "attribute1": value, 
        "attribute2": value,
         ...},
      "propertyID2": {
        "attribute1": value, 
        "attribute2": value,
         ...},
      ...},
    "nodeID2": {
       "propertyID1": { ... }, ...
   },
"deviceID2": { ...}
...
}

That way the message you receive from mqtt is actually mostly a path within your json ... you could split the string into an array using the "/" as a separator and check every level of the path for existence ...

1 Like

sorry, I only realize now that my proposition seems to be equivalent to the answer you had on StackOverflow ... so this might not help ... but do you really have a valid reason to have arrays of objects ? the only reason I see is if the IDs are not unique (and in this case why call them IDs ?)

1 Like

I am now starting to doubt that I do need arrays... let me go test with objects only. But I am still wondering how would one do it.... thank you.