# Feature request - function node context store getter which sets default value

**URL:** <https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166>\
**Category:** Feature Requests\
**Tags:** function-node, feature-request\
**Created:** [1 January 2024 05:16 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166 "2024-01-01T05:16:56Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![MrWolf](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/mrwolf/32/86830_2.png) [@MrWolf](https://discourse.nodered.org/u/MrWolf)\
**Post date:** [1 January 2024 05:16 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/1 "2024-01-01T05:16:56Z")

</div>

Hi,

I think it would be fantastically useful to extend the context store getter such that in a function node I could specify a default value when calling context/flow/global.get().

If the key is not found then the getter would create the default value/object and return that value or reference to that newly created object (ie a type of atomic get-and-set-if-not-exist operation).

I’m thinking that this would be particularly useful in the case of the value being an object. This way I’d be guaranteed to receive a reference to an object which I could use/update without needing to write a bunch of defensive boilerplate.

For instance (trivial example), on startup the flow context store is empty. I can then simply call the get and on first iteration create a default value & receive a reference to that default:

```Javascript
const timestampsArray = flow.getWithDefault(“timestamps”, [])
const newTimestamp = Date.now()
timestampsArray.push(newTimestamp)

```

…aaaand job done. Context store now contains:

```JSON
{timestamps: [1704084912228]}

```

On second iteration I get the reference to the now previously created timestamps object and the context store now contains:

```JSON
{timestamps: [1704084912228, 1704085334560]}

```

Very convenient & no need for defensive boilerplate, redundant setter calls, etc etc.

Wouldn’t mind if it’s a new method or simply extension of the existing .get() method.

What do you think?

---

<div class="post-metadata">

**Author:** ![meeki007](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/meeki007/32/12499_2.png) [@meeki007](https://discourse.nodered.org/u/meeki007)\
**Post date:** [1 January 2024 05:52 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/2 "2024-01-01T05:52:50Z")

</div>

I believe this covers your needs with minimal code

```auto
//Get flow.timestamps else create timestamp
var context_flow_timestampsArray = flow.get('timestamps') || [];
const newTimestamp = Date.now()
context_flow_timestampsArray.push(newTimestamp)

flow.set('timestamps', context_flow_timestampsArray);

return msg;

```

this works for objects. ---\> var context\_flow\_timestampsObjects = flow.get('timestamps') || {};

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [1 January 2024 09:11 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/3 "2024-01-01T09:11:45Z")

</div>

There are times when a default value would be useful. Consider the case where the value in context is a simple integer which needs to be defaulted to -1, but where 0 is a valid value. Then that technique does not work.

---

<div class="post-metadata">

**Author:** ![MrWolf](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/mrwolf/32/86830_2.png) [@MrWolf](https://discourse.nodered.org/u/MrWolf)\
**Post date:** [1 January 2024 09:42 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/4 "2024-01-01T09:42:50Z")

</div>

Thanks for the suggestion, however it misses the point.

I currently use the kind of defensive boilerplate that you’re suggesting - and that’s exactly what I’m trying to eliminate.

Not only can it get rather convoluted if the valid default case is falsey - but in the case of objects (and arrays being a type of object) your suggested code unnecessarily invokes the setter function every single time after the initial run.

What I’m asking for allows for clean, efficient, readable, and easily understood code.

---

<div class="post-metadata">

**Author:** ![ralphwetzel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ralphwetzel/32/53713_2.png) [@ralphwetzel](https://discourse.nodered.org/u/ralphwetzel)\
**Post date:** [1 January 2024 10:44 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/5 "2024-01-01T10:44:50Z")

</div>

> [@MrWolf](#):
>
> unnecessarily invokes the setter function every single time after the initial run

Which `setter` function is (additionally) invoked when using `||` rather than a (potential) `getWithDefault`?

> [@MrWolf](#):
>
> Not only can it get rather convoluted if the valid default case is falsey

That's exactly the use-case why the [Nullish coalescing operator (??)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing) had been introduced. Thus a clean and short way could be:

`const timestampsArray = flow.get(“timestamps”) ?? [];`

---

<div class="post-metadata">

**Author:** ![ralphwetzel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ralphwetzel/32/53713_2.png) [@ralphwetzel](https://discourse.nodered.org/u/ralphwetzel)\
**Post date:** [1 January 2024 10:59 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/6 "2024-01-01T10:59:58Z")

</div>

> [@MrWolf](#):
>
> What I’m asking for allows for clean, efficient, readable, and easily understood code.

There's an alternative already implemented in the codebase:

```auto
const timestampsArray = flow.get(“timestamps”, function(err, tA) {
    return tA ?? [];
})

```

This even allows you to fetch & process several contexts with one run:

```auto
flow.get([“timestamps”, "another"], function(err, tA, anth) {
    [...]
});

```

Details [here...](https://nodered.org/docs/user-guide/writing-functions#asynchronous-context-access)

---

<div class="post-metadata">

**Author:** ![MrWolf](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/mrwolf/32/86830_2.png) [@MrWolf](https://discourse.nodered.org/u/MrWolf)\
**Post date:** [1 January 2024 11:00 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/7 "2024-01-01T11:00:59Z")

</div>

> [@ralphwetzel](#):
>
> Which `setter` function is (additionally) invoked when using `||` rather than a (potential) `getWithDefault`?

```JavaScript
flow.set('timestamps', context_flow_timestampsArray);

```

This is redundant when receiving an object reference.

---

<div class="post-metadata">

**Author:** ![ralphwetzel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ralphwetzel/32/53713_2.png) [@ralphwetzel](https://discourse.nodered.org/u/ralphwetzel)\
**Post date:** [1 January 2024 11:04 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/8 "2024-01-01T11:04:30Z")

</div>

Now I - think I - get your point: The idea is to run an implicit `flow.set` in the background if the context isn't defined already.

---

<div class="post-metadata">

**Author:** ![MrWolf](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/mrwolf/32/86830_2.png) [@MrWolf](https://discourse.nodered.org/u/MrWolf)\
**Post date:** [1 January 2024 11:48 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/9 "2024-01-01T11:48:57Z")

</div>

Precisely. I ask for a value by key & provide a default value. If the key doesn’t exist then create the kvp and return either the default scalar value or the reference to the newly created default object (ie _as if that object already existed in the data store_).

What a lot of people don’t seem to understand is that if the context store kvp value exists & is an object then context/flow/global.get() returns a _reference_ to that object.

In this case manipulating what is returned directly affects the object in the context store. A subsequent .set() operation is entirely redundant.

Re the sample you provided -

```auto
const timestampsArray = flow.get(“timestamps”, function(err, tA) {
    return tA ?? [];
})

```

I don’t think this will actually work because:  
a) this signature is only valid for async data stores and hence doesn’t return values (instead, simply invoking function as a callback) - though I’m not 100% certain as I don’t have a chance to investigate for a few days, and  
b) probably more important - if a) was incorrect & it did indeed operate as you expect - whilst it returns the default value that default value is not persisted, so every invocation would simply yield the default value

Anyways - thanks for the suggestions!

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [1 January 2024 11:55 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/10 "2024-01-01T11:55:26Z")

</div>

> [@MrWolf](#):
>
> A subsequent .set() operation is entirely redundant.

That is only true for in memory context store. If you ever changed over to a persistent store then the set is required. It is recommended to always do a set even with objects.

---

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [1 January 2024 12:01 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/11 "2024-01-01T12:01:29Z")

</div>

> [@Colin](#):
>
> That is only true for in memory context store.

I also noticed this behavior and it is true that for a novice there is a risk of accidentally modifying their object. It may be necessary to deep clone the object?

---

<div class="post-metadata">

**Author:** ![ralphwetzel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ralphwetzel/32/53713_2.png) [@ralphwetzel](https://discourse.nodered.org/u/ralphwetzel)\
**Post date:** [1 January 2024 12:33 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/12 "2024-01-01T12:33:02Z")

</div>

> [@MrWolf](#):
>
> ```auto
> const timestampsArray = flow.get(“timestamps”, function(err, tA) {
> return tA ?? [];
> })
> 
> ```

You're right w/ a). One needed to get the values out of the callback function:

```auto
let timestampsArray;
flow.get(“timestamps”, function(err, tA) {
    timestampsArray = tA ?? [];
})

```

This yet isn't the focus of your request - as I understood meanwhile.

---

<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:** [1 March 2024 12:33 UTC](https://discourse.nodered.org/t/feature-request-function-node-context-store-getter-which-sets-default-value/84166/13 "2024-03-01T12:33:16Z")

</div>

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