# Boolean Function

**URL:** <https://discourse.nodered.org/t/boolean-function/73678>\
**Category:** General\
**Created:** [15 January 2023 00:46 UTC](https://discourse.nodered.org/t/boolean-function/73678 "2023-01-15T00:46:49Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![interscope101](https://avatars.discourse-cdn.com/v4/letter/i/a88e4f/32.png) [@interscope101](https://discourse.nodered.org/u/interscope101)\
**Post date:** [15 January 2023 00:46 UTC](https://discourse.nodered.org/t/boolean-function/73678/1 "2023-01-15T00:46:49Z")

</div>

Hi, I am trying to find the simplest approach to code the following. I have a Boolean function statement checking the state of multiple variables:

```auto
if (a > 2 && b >7 && c <5) { }

```

and for each variable I have a Boolean flag (saved in context from dashboard input) indicating whether the that variable should be included in the function, so if:

include\_a = true; include\_b = false; include\_c = true

the statement needs to be:

```auto
if (a > 2 && c <5) { }

```

Seems that there must be a more elegant solution than what I can come up, which a long list of list statements check for all variations (there are lot more variable than 3). Thanks!

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [15 January 2023 02:07 UTC](https://discourse.nodered.org/t/boolean-function/73678/2 "2023-01-15T02:07:27Z")

</div>

I hesitate to call it elegant but this function builds up the expression and then evals it,  
It expects the variables to arrive as an object with keys "a", "b", etc.  
Testing has been limited to the two inject strings and one flow variable shown!

![Untitled 1](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/5/5/55833e8ba6277a9f673978ac4ec698191b0e7eb4.jpeg)

Edit: simplified code

```auto
[{"id":"19154000c821042e","type":"inject","z":"7124eaac06216d5b","name":"flow.useb = true","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":160,"y":40,"wires":[["89606ab29439ffea"]]},{"id":"e1b39d51c46e251f","type":"inject","z":"7124eaac06216d5b","name":"flow.useb = false","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"false","payloadType":"bool","x":160,"y":80,"wires":[["89606ab29439ffea"]]},{"id":"89606ab29439ffea","type":"change","z":"7124eaac06216d5b","name":"","rules":[{"t":"set","p":"useb","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":390,"y":60,"wires":[[]]},{"id":"52ad7e216485bdc4","type":"function","z":"7124eaac06216d5b","name":"JiggeryPokery","func":"const reference = { // ALL possible variables\n \"a\": { \"testvalue\": 2, \"operator\": \">\", \"flowVar\":\"usea\"},\n \"b\": { \"testvalue\": 7, \"operator\": \">\", \"flowVar\":\"useb\"},\n \"c\": { \"testvalue\": 5, \"operator\": \"<\", \"flowVar\":\"usec\"},\n \"d\": { \"testvalue\": 19, \"operator\": \"<\", \"flowVar\": \"duntexist\" }, // flowVar need not exist\n }\nlet cmd = \"(\"\nfor (const key in reference) {\n if (msg.payload.hasOwnProperty(key)) {\n const usethisproperty = flow.get(reference[key].flowVar) ?? true \n if (usethisproperty) { \n cmd += msg.payload[key] + reference[key].operator + reference[key].testvalue + \" && \"\n } \n }\n}\ncmd += ' 1==1)'\nnode.warn(cmd)\nlet result = eval(cmd)\nnode.warn(result)","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":200,"wires":[[]]},{"id":"21f8da981884b87e","type":"inject","z":"7124eaac06216d5b","name":"{\"a\": 3, \"b\": 8, \"c\": 4}","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"a\": 3, \"b\": 8, \"c\": 4}","payloadType":"json","x":150,"y":200,"wires":[["52ad7e216485bdc4"]]},{"id":"94ba0372e2937a84","type":"inject","z":"7124eaac06216d5b","name":"{\"a\": 3, \"b\": 6, \"c\": 4}","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"a\": 3, \"b\": 6, \"c\": 4}","payloadType":"json","x":150,"y":240,"wires":[["52ad7e216485bdc4"]]}]

```

---

<div class="post-metadata">

**Author:** ![interscope101](https://avatars.discourse-cdn.com/v4/letter/i/a88e4f/32.png) [@interscope101](https://discourse.nodered.org/u/interscope101)\
**Post date:** [15 January 2023 05:18 UTC](https://discourse.nodered.org/t/boolean-function/73678/3 "2023-01-15T05:18:43Z")

</div>

Hi, thank you! Yes, seems to work - just need to understand it. Also, noticed 3 warnings in the function (line 10, 11, 18) including "eval can be harmful" (which I've never seen before).

What is the reason for having this in the end `cmd += ' 1==1)'` ? is it because otherwise the expression ends with && ?

```auto
const reference = { // ALL possible variables
    "a": { "testvalue": 2, "operator": ">", "flowVar":"usea"},
    "b": { "testvalue": 7, "operator": ">", "flowVar":"useb"},
    "c": { "testvalue": 5, "operator": "<", "flowVar":"usec"},
    "d": { "testvalue": 19, "operator": "<", "flowVar": "duntexist" }, // flowVar need not exist
    }
let cmd = "("
for (const key in reference) {
     if (msg.payload.hasOwnProperty(key)) {
        const usethisproperty = flow.get(reference[key].flowVar) ?? true 
        if (usethisproperty) { 
            cmd += msg.payload[key] + reference[key].operator + reference[key].testvalue + " && "
        }  
    }
}
cmd += ' 1==1)'
node.warn(cmd)
let result = eval(cmd)
node.warn(result)

```

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [15 January 2023 06:02 UTC](https://discourse.nodered.org/t/boolean-function/73678/4 "2023-01-15T06:02:02Z")

</div>

Yes, appending 1==1 is because there would otherwise be a floating &&.

eval can be harmful - Yes, the function effectively executes whatever code you feed it with.

An example, I have a global context variable "model".  
If I inject this payload` {"a":"node.warn(global.get('model'))"}` the node outputs this

 ![Untitled 1](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/7/c/7ca55cbb0d019c942bd0864b5ef922e468ecffd2.jpeg)

---

<div class="post-metadata">

**Author:** ![interscope101](https://avatars.discourse-cdn.com/v4/letter/i/a88e4f/32.png) [@interscope101](https://discourse.nodered.org/u/interscope101)\
**Post date:** [15 January 2023 06:13 UTC](https://discourse.nodered.org/t/boolean-function/73678/5 "2023-01-15T06:13:39Z")

</div>

There seems to be some "expected" syntax warnings line 10 and 11 yet it still works ... do you see them as well?

My flag variables are global localfile store global.get ('a', 'file') - where do I specify the file in flow.get(reference[key].flowVar)

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [15 January 2023 06:19 UTC](https://discourse.nodered.org/t/boolean-function/73678/6 "2023-01-15T06:19:02Z")

</div>

No, I don't know where you see these warnings - in Monaco editor?

> [@interscope101](#):
>
> My flag variables are global localfile store global.get ('a', 'file') - where do I specify the file in flow.get(reference[key].flowVar)

I don't understand the question, but it's early in the morning and pre coffee.

---

<div class="post-metadata">

**Author:** ![interscope101](https://avatars.discourse-cdn.com/v4/letter/i/a88e4f/32.png) [@interscope101](https://discourse.nodered.org/u/interscope101)\
**Post date:** [15 January 2023 06:40 UTC](https://discourse.nodered.org/t/boolean-function/73678/7 "2023-01-15T06:40:43Z")

</div>

You have the line: `const usethisproperty = flow.get(reference[key].flowVar)` - which gets the flow variables? Mine are global saved in file ... so I need to change the line to `const usethisproperty = global.get(reference[key].flowVar)` ... just not sure about the syntax to specify 'file'

> [@jbudd](#):
>
> No, I don't know where you see these warnings - in Monaco editor?

Don't remember which editor (the older version), here are the warnings

line 10  
expected identifier instead saw "?"  
expected ":" insteas saw true

line 10  
expected identifier instead saw "if"  
expected an operator instead saw "("  
expected an operator instead saw ")"  
missing semicolon

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [15 January 2023 06:54 UTC](https://discourse.nodered.org/t/boolean-function/73678/8 "2023-01-15T06:54:58Z")

</div>

I don't use filesystem context storage so I'm not sure how it works. I should learn about it.

The first warning is because the `?? true` syntax requires node.js 14 or above (I think).  
If you have an older version use `|| true`

I have given up semicolons for New Year. So far my code is a tiny bit slimmer. Add them if you like. 😀

ps You can protect the function code from malicious/accidental javascript injection by changing the for loop like this

```auto
for (const key in reference) {
    if (msg.payload.hasOwnProperty(key)) {
        const num = msg.payload[key]
        if (typeof(num) == "number") {
           const usethisproperty = flow.get(reference[key].flowVar) ?? true 
           if (usethisproperty) { 
               cmd += num + reference[key].operator + reference[key].testvalue + " && "
           }  
        }
    }
}

```

pps The square bracket notation is needed because the "key" in "reference.key.flowVar" would be interpreted as a literal not a variable.  
If your global context variable is "a" and you normally access it by global.get ('a', 'file'), I _assume_ that `global.get(reference.a.flowVar, 'file')` would work.  
In the function that would be `global.get(reference[key].flowVar, 'file')`

---

<div class="post-metadata">

**Author:** ![interscope101](https://avatars.discourse-cdn.com/v4/letter/i/a88e4f/32.png) [@interscope101](https://discourse.nodered.org/u/interscope101)\
**Post date:** [15 January 2023 07:14 UTC](https://discourse.nodered.org/t/boolean-function/73678/9 "2023-01-15T07:14:23Z")

</div>

> [@jbudd](#):
>
> use `|| true`

Indeed! This actually took care of all warnings - including semicolons 🙂

As far as filesystem context storage there is a small adjustment in the settings file and the code becomes: flow.set ('variable', value, 'file') and flow.get ('variable', 'file'). So I am trying to figure out if I simply need to change your line to `flow.get(reference[key].flowVar, 'file')` ?

---

<div class="post-metadata">

**Author:** ![interscope101](https://avatars.discourse-cdn.com/v4/letter/i/a88e4f/32.png) [@interscope101](https://discourse.nodered.org/u/interscope101)\
**Post date:** [15 January 2023 07:31 UTC](https://discourse.nodered.org/t/boolean-function/73678/10 "2023-01-15T07:31:49Z")

</div>

> [@interscope101](#):
>
> 'file'

Jus tried that, something is not working. Also, one of my variables is string, is this correct?

```auto
    "A": { "testvalue": "SB", "operator": "===", "flowVar":"use_A"},

```

---

<div class="post-metadata">

**Author:** ![interscope101](https://avatars.discourse-cdn.com/v4/letter/i/a88e4f/32.png) [@interscope101](https://discourse.nodered.org/u/interscope101)\
**Post date:** [15 January 2023 07:42 UTC](https://discourse.nodered.org/t/boolean-function/73678/11 "2023-01-15T07:42:34Z")

</div>

Sorry, stuck on a simple thing. What would this look like without injection node, just values defined in function and I can set the flag variables individually (no need to put them in the loop)

```auto
let a = "SB"
let b = 2
let c = 9

let use_a = false
let use_b = true
let use c = true

const reference = { 
    "a": { "testvalue": "SB", "operator": "===", "flowVar":"use_A"},
    "b": { "testvalue": 7, "operator": ">", "flowVar":"useb"},
    "c": { "testvalue": 5, "operator": "<", "flowVar":"usec"},
    "d": { "testvalue": 19, "operator": "<", "flowVar": "duntexist" }, // flowVar need not exist
    }
let cmd = "("

for (const key in reference) {
    if (msg.payload.hasOwnProperty(key)) {
        const num = msg.payload[key]
        if (typeof(num) == "number") {
            const usethisproperty = flow.get(reference[key].flowVar, 'file') || true 
           if (usethisproperty) { 
               cmd += num + reference[key].operator + reference[key].testvalue + " && "
           }  
        }
    }
}

cmd += '1==1)'
node.warn(cmd)
let result = eval(cmd)
node.warn(result)

```

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [15 January 2023 07:45 UTC](https://discourse.nodered.org/t/boolean-function/73678/12 "2023-01-15T07:45:59Z")

</div>

> [@interscope101](#):
>
> `if (a > 2 && b >7 && c <5) { }`

Specification creep!

If some of your data can be a string, you can't sanitise it with

```auto
const num = msg.payload[key]
if (typeof(num) == "number") {
...
}

```

or it will never test the value of A.

---

<div class="post-metadata">

**Author:** ![interscope101](https://avatars.discourse-cdn.com/v4/letter/i/a88e4f/32.png) [@interscope101](https://discourse.nodered.org/u/interscope101)\
**Post date:** [15 January 2023 08:17 UTC](https://discourse.nodered.org/t/boolean-function/73678/13 "2023-01-15T08:17:27Z")

</div>

> [@interscope101](#):
>
> if (a \> 2 && b \>7 && c \<5) { }

I see; didn't occur that there would be a difference in code, should have said

```auto
if (a > 2 && b >7 && a == "abc") { }

```

the good news is that `const usethisproperty = global.get(reference[key].flowVar, 'file') ` is working

---

<div class="post-metadata">

**Author:** ![interscope101](https://avatars.discourse-cdn.com/v4/letter/i/a88e4f/32.png) [@interscope101](https://discourse.nodered.org/u/interscope101)\
**Post date:** [15 January 2023 08:50 UTC](https://discourse.nodered.org/t/boolean-function/73678/14 "2023-01-15T08:50:31Z")

</div>

I guess I can convert that string to number. The only thing I still can't figure out is how to specify the  
a: "testvalue" in the function as just a = 200 rather than the msg.payload format.

```auto
let x = global.get('ex', 'file')
let y = "2"

const reference = { 
    "a": { "testvalue": x, "operator": "==", "flowVar":"iSm5"},
    "b": { "testvalue": y, "operator": ">", "flowVar":"pr"}
    }
let cmd = "("

for (const key in reference) {
    if (msg.payload.hasOwnProperty(key)) {
        const num = msg.payload[key]
        if (typeof(num) == "number") {
            const usethisproperty = global.get(reference[key].flowVar, 'file')  
           if (usethisproperty) { 
               cmd += num + reference[key].operator + reference[key].testvalue + " && "
           }  
        }
    }
}

cmd += '1==1)'
node.warn(cmd)
let result = eval(cmd)
node.warn(result)

```

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [15 January 2023 09:21 UTC](https://discourse.nodered.org/t/boolean-function/73678/15 "2023-01-15T09:21:31Z")

</div>

Special handling for strings, I also tested it works with boolean (c):

```auto
const reference = { // ALL possible variables
    "a": { "testvalue": "abc", "operator": "===", "flowVar":"usea"},
    "b": { "testvalue": 7, "operator": ">", "flowVar":"useb"},
    "c": { "testvalue": false, "operator": "===", "flowVar":"usec"},
    "d": { "testvalue": 19, "operator": "<", "flowVar": "duntexist" }, // flowVar need not exist
    }
let cmd = "("
for (const key in reference) {
    if (msg.payload.hasOwnProperty(key)) {
        const usethisproperty = flow.get(reference[key].flowVar) ?? true 
        if (usethisproperty) { 
            let testvalue = reference[key].testvalue
            if (typeof (testvalue) == "string") { // if this is a string, wrap it in single quotes
                testvalue = "'" + testvalue + "'"
                msg.payload[key] = "'" + msg.payload[key] + "'"
            }
           cmd += msg.payload[key] + reference[key].operator + testvalue + " && "
        }
    }
}
cmd += ' 1==1)'
node.warn(cmd)
let result = eval(cmd)
node.warn(result)

```

---

<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:** [15 January 2023 11:11 UTC](https://discourse.nodered.org/t/boolean-function/73678/16 "2023-01-15T11:11:52Z")

</div>

> [@jbudd](#):
>
> The first warning is because the `?? true` syntax requires node.js 14 or above (I think).

Correct. And Node.js v14 LTS should be the minimum version you should be using now since v12 is out of support.

> [@jbudd](#):
>
> I have given up semicolons for New Year. So far my code is a tiny bit slimmer.

Good for you! I also dropped them a long time back. I use a slightly modified (read less-annoying) version of JavaScript "Standard" for my formatting these days. That also doesn't use `;`.

> [@jbudd](#):
>
> don't use filesystem context storage so I'm not sure how it works. I should learn about it.

It is the same as the default memory storage but it copies the data to a file every nn seconds (20 or 30 I think but you can adjust it). Of course, it also has to serialise the data so some things you can keep in memory storage will change when saved to file.

---

<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:** [15 January 2023 11:14 UTC](https://discourse.nodered.org/t/boolean-function/73678/17 "2023-01-15T11:14:12Z")

</div>

I would add a test to make sure that the operator value is a valid operator, that would avoid the danger of accidentally sending something damaging.

---

<div class="post-metadata">

**Author:** ![interscope101](https://avatars.discourse-cdn.com/v4/letter/i/a88e4f/32.png) [@interscope101](https://discourse.nodered.org/u/interscope101)\
**Post date:** [15 January 2023 18:28 UTC](https://discourse.nodered.org/t/boolean-function/73678/18 "2023-01-15T18:28:30Z")

</div>

> [@TotallyInformation](#):
>
> Correct. And Node.js v14 LTS should be the minimum version you should be using now since v12 is out of support.

I actually got Node.js version v16.19.0 running - so I don't think it was that

---

<div class="post-metadata">

**Author:** ![interscope101](https://avatars.discourse-cdn.com/v4/letter/i/a88e4f/32.png) [@interscope101](https://discourse.nodered.org/u/interscope101)\
**Post date:** [15 January 2023 18:37 UTC](https://discourse.nodered.org/t/boolean-function/73678/19 "2023-01-15T18:37:38Z")

</div>

Thanks! I am embarrassingly still stuck on a simple part: my variables are not coming via msg.payload; retrieving everything from context. So would would this look like if I simply have them defined inside function: let a = acc, let b = 5, let c = true ?

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [15 January 2023 18:53 UTC](https://discourse.nodered.org/t/boolean-function/73678/20 "2023-01-15T18:53:02Z")

</div>

Rather than rewriting the code to allow for data not in msg.payload, rewrite payload to include the data. Could be in a seperate function or at the top of the JiggeryPokery one.

```auto
const a = "abc"
const b = 6
const c = global.get("valueOfC") 
msg.payload = {"a": a, "b": b, "c": c}

```

[Next page](https://discourse.nodered.org/t/boolean-function/73678.md?page=2)
