Creating percentages from responses

Hi all...

Apologies, I'm a very new user with no experience in coding...

Does anyone have any ideas on how best to count from 4 responses in a message and create percentage results to be sent via OSC?

Would it be possible to make this with nodes alone or does it require Javascript?

The message format the host app outputs is below:
{
"id" : 484993,
"content_type" : null,
"object_id" : null,
"response_obj" : {
"id" : 227825,
"pollresponse" : 484993,
"response" : [ 42834, 42835, 42836, 42837 ]
},
"response_type" : "choice",
"is_active" : true,
"created" : "2019-06-11T14:40:57.794723Z",
"updated" : "2019-06-11T14:45:10.646746Z",
"anonymous_id" : null,
"archive" : null,
"poll" : 31754,
"person" : 355244
}

Any input would be greatly appreciated.
Many thanks
Patrick

You have not made it clear (to me at least) exactly what percentages you want to see. Perhaps tell us exactly what you want to get from the data you have showed, and how it is calculated.

Hi Patrick,

I assume you mean you want the payload.response_obj.response array of values to be turned into their equivalent percentages. Is payload.response_obj.pollresponse the total? Or do you also need to sum the values in that array first to get the total?

Sorry for not making myself clear...

The host application is a voting app with 4 options of response -
"response" : [ 42834, 42835, 42836, 42837 ]

Option a - 42834
Option b - 42835
Option c - 42836
Option d - 42837

I need to be able to collect all the responses and output the percentage results - 0-100 between all the responses that come through.

Does that make sense?

There isn't a node I know of that will just do that (although the flow library is large and something may lurk in there).

Given the core palette of nodes, you're left with either the Function node or Change node.

With the Change node, you can configure it to set msg.results to the Expression:

$map(payload.response_obj.response, function($v) { $round(100*$v/( $sum := function($i, $j){$i + $j}; $reduce(payload.response_obj.response, $sum) ),2)})

This uses the JSONata expression language.

Or, a Function node with the code:

var total = 0;
msg.results = [];
// First get the total from the array
msg.payload.response_obj.response.forEach(function(v) {
   total += v
});
// The calculate each value's percentage to 2 decimal places
msg.payload.response_obj.response.forEach(function(v) {
   msg.results.push( (100*v/total).toFixed(2)  )
});
return msg;

Both will give you msg.results with the array of percentages.

Thank you very much...

Would this script give me the ability to output the 4 separate percentages and link them into an OSC output node?

How do I get the 4 options into that script and output 4 separate percentages?

Does the flow given not work?

When I connect the input MQTT node into the funtion node I get the following error in the Debug window..."TypeError: Cannot read property 'response' of undefined"

As I said, I'm very new to this so I probably missing something very simple...

That is presumably coming from one of the lines like
msg.payload.response_obj.response.forEach(..
and means that msg.payload does not contain and object called response_obj even though the data you showed at the start does contain such an object.
Put a debug node showing what is going into the function node and copy/paste what you see here.

I selected the second option and the following is what can through to the debug node:

"{"id": 484993, "content_type": null, "object_id": null, "response_obj": {"id": 227825, "pollresponse": 484993, "response": [42834]}, "response_type": "choice", "is_active": true, "created": "2019-06-11T14:40:57.794723Z", "updated": "2019-06-12T12:44:23.898007Z", "anonymous_id": null, "archive": null, "poll": 31754, "person": 355244}"

Note that that is a string, not a javascript object, which you did not tell us before. If you feed that through a JSON node it should convert it to a javascript object. Try that after looking at what the JSON node passes on and making sure it looks ok.

What do you mean by that?

Sorry.
This is what came through after going through a JSON node -

object
id: 484993
content_type: null
object_id: null
response_obj: object
id: 227825
pollresponse: 0x76681
response: array[1]
0: 42834
response_type: "choice"
is_active: true
created: "2019-06-11T14:40:57.794723Z"
updated: "2019-06-12T12:58:13.074971Z"
anonymous_id: null
archive: null
poll: 31754
person: 355244

The source is a 4 option voting question, which is what I'm trying to aggregate the results from.
This is the message I get when option 2 is selected.

Apologies, I don't think I'm explaining myself very well.

My source is a multiple choice voting app that I need to capture each answer that comes through and display a number from 0-100 for each result.

The source app uses an Ably Realtime feed to broadcast when a user has selected an answer.
This is coming into Node-RED as a MQTT feed.

Below is the source web app:

When I select the second option and submit the following message comes through.

object
id: 484993
content_type: null
object_id: null
response_obj: object
id: 227825
pollresponse: 0x76681
response: array[1]
0: 42836
response_type: "choice"
is_active: true
created: "2019-06-11T14:40:57.794723Z"
updated: "2019-06-12T13:15:06.381463Z"
anonymous_id: null
archive: null
poll: 31754
person: 355244

Does that make more sense?

Many thanks
Patrick

The important thing is what is in the message, which now looks ok, so what now happens when you feed it into the function node?

Below is what comes out of the Function node into the debug node.

object
id: 484993
content_type: null
object_id: null
response_obj: object
id: 227825
pollresponse: 484993
response: array[1]
0: 42836
response_type: "choice"
is_active: true
created: "2019-06-11T14:40:57.794723Z"
updated: "2019-06-12T13:45:22.039299Z"
anonymous_id: null
archive: null
poll: 31754

It looks exactly the same as what comes out of the JSON node?

Look carefully at the code in function node. Where does it save the results? Then change the debug node to 'Show Entire Message' and try again.

Ah, yes thanks!
I'm getting this now when I select all four options:

results: array[4]
0: "25.00"
1: "25.00"
2: "25.00"
3: "25.00"

Can I separate each result value and pipe into a separate OSC node?