# Global context mutability

**URL:** <https://discourse.nodered.org/t/global-context-mutability/22407>\
**Category:** General\
**Created:** [29 February 2020 12:54 UTC](https://discourse.nodered.org/t/global-context-mutability/22407 "2020-02-29T12:54:18Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![shooftie](https://avatars.discourse-cdn.com/v4/letter/s/ee7513/32.png) [@shooftie](https://discourse.nodered.org/u/shooftie)\
**Post date:** [29 February 2020 12:54 UTC](https://discourse.nodered.org/t/global-context-mutability/22407/1 "2020-02-29T12:54:18Z")

</div>

I have a function-file node in which I would like to use configs which are stored in the global context.

I am struggling because my approach appears to mutate the global context which I do not want. I am not sure whether I am misunderstanding Node-red, JavaScript or what?

The basic principle is that there is a bunch of config in the global context for sensors and devices. Sensors reference the device upon which they are mounted. Devices reference the room in which they are located.

```auto
global.const = {
  sensors: [
    {
      name: 'sensor_light_1',
      device: 'room_1',
    },
    {
      name: 'sensor_humidity',
      device: 'room_1',
    },
    {
      name: 'sensor_temp',
      device: 'room_2',
    }
  ],
  devices: [
    {
      name: 'room_1',
      location: 'bedroom',
    },
    {
      name: 'room_2',
      location: 'kitchen',
    }
  ]
}

```

I would like to be able to create a means of retrieving a sensor config and replacing the reference to the device with the device's config:

```auto
// Transforming this
{
  name: 'sensor_light_1',
  device: 'room_1',
}

// Into this
{
  name: 'sensor_light_1',
  device: {
   name: 'room_1',
   location: 'bedroom',
  }
}

```

However, my approach seems to modify the Global context replacing the sensor config with the combined result.

A simplified example is here:

```auto
class Sensors {
  constructor(config) {
    this.sensors = config.sensors;
    this.devices = config.devices;
  }

  getSensor(sensorName) {
    // Find the sensor config with the matching name
    const sensor = this.sensors
      .find((sensor) => sensor.name === sensorName);

    // Pass the config to a method with replaces the
    // device name property with that device's config
    return this.addDevice(sensor);
  }

  addDevice(sensor) {
    const sensorWithDevice = sensor;

    // Find the device config with the matching name
    const sensorDevice = this.devices
      .find((device) => device.name === sensor.device);

    // Replace the name property in the sensor config
    // with the device config
    sensorWithDevice.device = sensorDevice;

    return sensorWithDevice;
  }
}

const sensors = new Sensors({
  sensors: global.get('const').sensors,
  devices: global.get('const').devices,
});

msg.payload = sensors.getSensor('sensor_light_1');

return msg;

```

---

<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:** [29 February 2020 13:13 UTC](https://discourse.nodered.org/t/global-context-mutability/22407/2 "2020-02-29T13:13:16Z")

</div>

JavaScript passes objects by reference and we don't automatically clone them for you for performance reasons. If you want to modify the object without affecting context, you have to clone it or rebuild it.

> [@Global.put not needed as variable altered by reference?](https://discourse.nodered.org/t/global-put-not-needed-as-variable-altered-by-reference/20511/5):
>
> JavaScript passes objects around by reference rather than by value. So the call to global.get() returns a reference to the object in context. Any modification of the object will modify the object in context. If you want to modify the object without modifying what is in context, you have to clone it first. We provide the RED.util.cloneMessage function that can be used for this: var value = RED.util.cloneMessage( global.get("myValue") );

---

<div class="post-metadata">

**Author:** ![shooftie](https://avatars.discourse-cdn.com/v4/letter/s/ee7513/32.png) [@shooftie](https://discourse.nodered.org/u/shooftie)\
**Post date:** [29 February 2020 13:17 UTC](https://discourse.nodered.org/t/global-context-mutability/22407/3 "2020-02-29T13:17:11Z")

</div>

It would, therefore, appear to be my ignorance.

Thank you so much for your speedy response. I'll post back with the modified code for the benefit of the next naive soul.

Many thanks.

---

<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:** [29 February 2020 16:43 UTC](https://discourse.nodered.org/t/global-context-mutability/22407/4 "2020-02-29T16:43:00Z")

</div>

Just for fun, a solution using jsonata, passing the original object as `inp1`

```auto
$map(
   inp1.sensors,
   function($v, $i, $a) {
       {
           "name" : $v.name,
           "device" : inp1.devices[name=$v.device]
       } 
   }
)

```

Testing flow:

```auto
[{"id":"f40003a7.9b24c","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"81f2584b.e458a8","type":"inject","z":"f40003a7.9b24c","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":240,"y":160,"wires":[["6030a7f8.16b498"]]},{"id":"6030a7f8.16b498","type":"function","z":"f40003a7.9b24c","name":"Dataset","func":"msg.inp1= {\n sensors: [\n {\n name: 'sensor_light_1',\n device: 'room_1',\n },\n {\n name: 'sensor_humidity',\n device: 'room_1',\n },\n {\n name: 'sensor_temp',\n device: 'room_2',\n }\n],\n devices: [\n {\n name: 'room_1',\n location: 'bedroom',\n },\n {\n name: 'room_2',\n location: 'kitchen',\n }\n]\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":410,"y":160,"wires":[["3a8db7c1.a3c548","dea41cbb.f370a"]]},{"id":"908406a9.d219a8","type":"debug","z":"f40003a7.9b24c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":730,"y":160,"wires":[]},{"id":"3a8db7c1.a3c548","type":"change","z":"f40003a7.9b24c","name":"","rules":[{"t":"set","p":"out1","pt":"msg","to":"$map(\t inp1.sensors,\t function($v, $i, $a) {\t {\t \"name\" : $v.name,\t \"device\" : inp1.devices[name=$v.device]\t } \t }\t)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":570,"y":160,"wires":[["908406a9.d219a8"]]},{"id":"dea41cbb.f370a","type":"debug","z":"f40003a7.9b24c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":560,"y":100,"wires":[]}]

```

---

<div class="post-metadata">

**Author:** ![shooftie](https://avatars.discourse-cdn.com/v4/letter/s/ee7513/32.png) [@shooftie](https://discourse.nodered.org/u/shooftie)\
**Post date:** [20 March 2020 20:28 UTC](https://discourse.nodered.org/t/global-context-mutability/22407/5 "2020-03-20T20:28:43Z")

</div>

Not really very enlightening...

```auto
...
const config = RED.util.cloneMessage(global.get('const'));
const sensors = new Sensors({
  sensors: config.sensors,
  devices: config.devices,
});

msg.payload = sensors.getSensor('sensor_light_1');

return msg;

```

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [19 May 2020 20:28 UTC](https://discourse.nodered.org/t/global-context-mutability/22407/6 "2020-05-19T20:28:44Z")

</div>

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.
