# How to store data in context hierarchichally

**URL:** <https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287>\
**Category:** General\
**Created:** [19 May 2019 13:36 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287 "2019-05-19T13:36:13Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![hazymat](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hazymat/32/108159_2.png) [@hazymat](https://discourse.nodered.org/u/hazymat)\
**Post date:** [19 May 2019 13:36 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/1 "2019-05-19T13:36:13Z")

</div>

This is probably a really basic question.

This seems to work fine:

```
global.set("WaterSupplyUnit.LeakZone1",true)

```

An expandable object appears in context explorer, with "LeakZone1" as an available subvalue.

But if I want to store "sub sub values" like this:

```
global.set("WaterSupplyUnit.LeakZone1.leak", true)
global.set("WaterSupplyUnit.LeakZone1.leakdate", new Date().toLocaleDateString())
global.set("WaterSupplyUnit.LeakZone1.leaktime", new Date().toLocaleTimeString())

```

the values are not stored.

So it seems I can go "one deep" but no further.

Obvs I'm doing something wrong here!

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [19 May 2019 13:52 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/2 "2019-05-19T13:52:02Z")

</div>

It is easier to do something like:

```javascript
var dt = new Date().toLocaleDateString()
var WaterSupplyUnit = {
    LeakZone1: {
        leak: true,
        leakdate: dt,
        leaktime: dt,
    }
}
global.set("WaterSupplyUnit", WaterSupplyUnit)

```

---

<div class="post-metadata">

**Author:** ![hazymat](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hazymat/32/108159_2.png) [@hazymat](https://discourse.nodered.org/u/hazymat)\
**Post date:** [19 May 2019 13:53 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/3 "2019-05-19T13:53:02Z")

</div>

Thanks for the advice. Will do that. Also it's a bit clearer to read.

---

<div class="post-metadata">

**Author:** ![knolleary](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/knolleary/32/3_2.png) [@knolleary](https://discourse.nodered.org/u/knolleary)\
**Post date:** [19 May 2019 13:54 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/4 "2019-05-19T13:54:21Z")

</div>

If you have already set `WaterSupplyUnit.LeakZone1` to a Boolean type as per your first example, you cannot set sub properties of it. Only Objects can have properties.

---

<div class="post-metadata">

**Author:** ![hazymat](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hazymat/32/108159_2.png) [@hazymat](https://discourse.nodered.org/u/hazymat)\
**Post date:** [19 May 2019 14:32 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/5 "2019-05-19T14:32:19Z")

</div>

[EDITED]

So I've cleared the WaterSupplyUnit object (by deleting in context explorer) as Nick implies I should.

But with the snippet from @TotallyInformation, I am getting a different problem

It now deletes values from other zones when I post a given zone.

I think I know why (I'm writing the whole object), but what's the best way to not overwrite the whole object in this case?

```auto
var d = new Date().toLocaleDateString()
var t = new Date().toLocaleTimeString()
var WaterSupplyUnit

switch (msg.payload) {
    case "ZONE 1 LEAK = TRUE" :
    WaterSupplyUnit = { LeakZone1: { leak: true, leakdate: d, leaktime: t, } }
    global.set("WaterSupplyUnit", WaterSupplyUnit)
    break;

    case "ZONE 2 LEAK = TRUE" :
    WaterSupplyUnit = { LeakZone2: { leak: true, leakdate: d, leaktime: t } }
    global.set("WaterSupplyUnit", WaterSupplyUnit)    
    break;

    case "ZONE 3 LEAK = TRUE" :
    WaterSupplyUnit = { LeakZone3: { leak: true, leakdate: d, leaktime: t } }
    global.set("WaterSupplyUnit", WaterSupplyUnit)    
    break;

    case "ZONE 4 LEAK = TRUE" :
    WaterSupplyUnit = { LeakZone4: { leak: true, leakdate: d, leaktime: t } }
    global.set("WaterSupplyUnit", WaterSupplyUnit)    
    break;
    
    case "ZONE 1 LEAK = FALSE" :
    WaterSupplyUnit = { LeakZone1: { leak: false, leakdate: d, leaktime: t } }
    global.set("WaterSupplyUnit", WaterSupplyUnit)    
    break;
    
    case "ZONE 2 LEAK = FALSE" :
    WaterSupplyUnit = { LeakZone2: { leak: false, leakdate: d, leaktime: t } }
    global.set("WaterSupplyUnit", WaterSupplyUnit)    
    break;

    case "ZONE 3 LEAK = FALSE" :
    WaterSupplyUnit = { LeakZone3: { leak: false, leakdate: d, leaktime: t } }
    global.set("WaterSupplyUnit", WaterSupplyUnit)    
    break;

    case "ZONE 4 LEAK = FALSE" :
    WaterSupplyUnit = { LeakZone4: { leak: false, leakdate: d, leaktime: t } }
    global.set("WaterSupplyUnit", WaterSupplyUnit)    
    break;

}
return msg;

```

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [19 May 2019 15:20 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/6 "2019-05-19T15:20:49Z")

</div>

Get it...  
`var currentValue = global.get("WaterSupplyUnit") || {};`

Update it...  
`currentValue.this = that;`

Store it...  
global.set

---

<div class="post-metadata">

**Author:** ![Andrei](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/andrei/32/10446_2.png) [@Andrei](https://discourse.nodered.org/u/Andrei)\
**Post date:** [19 May 2019 15:49 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/7 "2019-05-19T15:49:12Z")

</div>

Point one: The pattern that Steve mentioned has to be respected. When updating context we get the context, update it and store it back.

Point two: The general idea seems to be: create an updated object and then use it to update the main object.

Based on your first post and further comments it could be done with this function:

```auto
let pay = global.get("WaterSupplyUnit" || {});

function updateStatus() { 
    let ustatus = {};
    ustatus.leak = true;
    ustatus.leakdate = new Date().toLocaleDateString();
    ustatus.leaktime = new Date().toLocaleTimeString();
    return ustatus;
}

switch (msg.payload) {
    case "ZONE 1 LEAK = TRUE" :
    global.set("WaterSupplyUnit.LeakZone1", updateStatus());
    break;

    case "ZONE 2 LEAK = TRUE" :
    global.set("WaterSupplyUnit.LeakZone2", updateStatus());    
    break;

    case "ZONE 3 LEAK = TRUE" :
    global.set("WaterSupplyUnit.LeakZone3", updateStatus());   
    break;

    case "ZONE 4 LEAK = TRUE" :
    global.set("WaterSupplyUnit.LeakZone4", updateStatus());   
    break;
}
    
    return msg;

```

Edit: first line is useless.. and I am not respecting point 1, 😂

Now I have to understand why it works, 🤣 but only after the lunch...

---

<div class="post-metadata">

**Author:** ![Andrei](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/andrei/32/10446_2.png) [@Andrei](https://discourse.nodered.org/u/Andrei)\
**Post date:** [19 May 2019 16:29 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/8 "2019-05-19T16:29:29Z")

</div>

I remember now.. this is a behaviour that is not intutive (but nice).

Javascript will not be happy with below code. Of course I can not assign a value to property `c` given that `b` is undefined.

```auto
let a = {};
a.b.c = "testing";
return msg;

```

Node-RED (global.set or the switch node) will happily accept an statement like below, even if `a` and `b` are not defined upfront:

```auto
global.set("a.b.c", "123");
return msg;

```

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [19 May 2019 17:07 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/9 "2019-05-19T17:07:24Z")

</div>

Hi, firstly, what generates the payload "ZONE 1 LEAK = TRUE"?  
If you do, then I'd suggest a simplification e.g. send `msg.leak = true` and `msg.zone = 1`

Anyhow, try this...

```auto
  var d = new Date().toLocaleDateString()
  var t = new Date().toLocaleTimeString()  

  //get existing object from global
  var WaterSupplyUnit = global.get("WaterSupplyUnit") || {};
  
  //get the zone number and TRUE/FALSE
  var r = /ZONE (\d+) LEAK = (TRUE|FALSE)/gm
  var x = r.exec(msg.payload);
  var zone = x[1];//get ZONE number from regex result
  var tf = x[2] == "TRUE"; //get TRUE or FALSE from regex result
  
  WaterSupplyUnit["LeakZone" + zone] = { leak: tf, leakdate: d, leaktime: t } };

  //store object back into global
  global.set("WaterSupplyUnit",WaterSupplyUnit);

```

Point of note: This will update the date/time even if leak is false - you may wish to only update the `leakdate` if `leak == true`

Also, note, I have not considered what what will happen if the payload is not formatted correctly or if the regex fails (I'll let you handle that)

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [19 May 2019 18:02 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/10 "2019-05-19T18:02:32Z")

</div>

If you have lots (or an unknown number) of leakzones, and as the data is an object rather than an array, you can simplify processing and reduce code by using the object keys as an array.

```javascript
//get existing object from global
var WaterSupplyUnit = global.get("WaterSupplyUnit") || {};

var keys = Object.keys(WaterSupplyUnit)
keys.forEach(function(unit, index) {
    ...
}

```

---

<div class="post-metadata">

**Author:** ![hazymat](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hazymat/32/108159_2.png) [@hazymat](https://discourse.nodered.org/u/hazymat)\
**Post date:** [19 May 2019 18:49 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/11 "2019-05-19T18:49:58Z")

</div>

Hi @Steve-Mcl, @TotallyInformation, and @Andrei

I've always been a bit too lazy to think about objects properly, so thanks for kicking me on that one. I'll go with a hybrid of Steve and Julian's suggestion.

> [@Steve-Mcl](#):
>
> Hi, firstly, what generates the payload "ZONE 1 LEAK = TRUE"?

My arduino sends the message over MQTT. (So yes, me.) It's a bit of a stupid way to do it. In the past I've used codes like 0;1 meaning a leak detected on sensor 0, I should have done that. Will probably change it.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [19 May 2019 19:14 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/12 "2019-05-19T19:14:13Z")

</div>

> [@hazymat](#):
>
> a bit too lazy to think about objects properly

Hmm, well not really a good approach for JavaScript where everything is an object of some sort! 🙂

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [19 May 2019 20:04 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/13 "2019-05-19T20:04:19Z")

</div>

> [@hazymat](#):
>
> My arduino sends the message over MQTT. (So yes, me.)

In which case, I would suggest you build this object, complete with timestamp at source (on the Arduino) and send the object as JSON. Then at node-red side simply feed the MQTT JSON string into a JSON node to rebuild the object.

And the beauty of MQTT, you don't have to change your existing methods of sending a string, just add code to build the object and send it on a different topic meaning you have backwards compatibility.

---

<div class="post-metadata">

**Author:** ![Andrei](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/andrei/32/10446_2.png) [@Andrei](https://discourse.nodered.org/u/Andrei)\
**Post date:** [19 May 2019 23:48 UTC](https://discourse.nodered.org/t/how-to-store-data-in-context-hierarchichally/11287/14 "2019-05-19T23:48:16Z")

</div>

I also think that the JavaScript switch statement generates a clumsy code as it get large.

Alternatively can use an object (always objects) to make the code simpler:

```auto
let dic = {
    "ZONE 1 LEAK = TRUE" : "WaterSupplyUnit.LeakZone1",
    "ZONE 2 LEAK = TRUE" : "WaterSupplyUnit.LeakZone2",
    "ZONE 3 LEAK = TRUE" : "WaterSupplyUnit.LeakZone3",
    "ZONE 4 LEAK = TRUE" : "WaterSupplyUnit.LeakZone4"
}

function updateStatus() { 
    let ustatus = {};
    ustatus.leak = true;
    ustatus.leakdate = new Date().toLocaleDateString();
    ustatus.leaktime = new Date().toLocaleTimeString();
    return ustatus;
}

let zone = dic[msg.payload];
global.set(zone, updateStatus());
return msg;

```
