Loop through an array and return index of a specific value

Hey Guys,

I have a flow that does a query on my energy provider and this returns an array with 120 objects in it (1/2 hour increments of pricing for electricity)

The first x (arbitrary number) of these are in the past and are differentiated by a date and time, but more easily by a value in a field of ACTUAL, whereas anything in the future is designated with FORECAST in the same field

What i would like to do is to loop through the array until i find the first object that is a FORECAST and then return the next 20 elements in the array.

Is there a way to do this with standard nodes before i sit down and try to write a function to do this ?

Here is the current flow which can be run and returns the results.

[{"id":"6028717e.571d7","type":"inject","z":"88029ce.abbab6","name":"Check Prices","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"300","topic":"","payload":"","payloadType":"date","x":230,"y":500,"wires":[["416043a5.94179c"]]},{"id":"416043a5.94179c","type":"function","z":"88029ce.abbab6","name":"set headers and change Postcode here","func":"msg.headers = {};\nmsg.headers[\"Content-Type\"] = \"application/json\";\nmsg.payload = '{ \"postcode\":\"2069\" }';\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":400,"y":440,"wires":[["a2b6857.bc69078"]]},{"id":"a2b6857.bc69078","type":"http request","z":"88029ce.abbab6","name":"","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://api.amberelectric.com.au/prices/listprices","tls":"","persist":false,"proxy":"","authType":"","x":430,"y":540,"wires":[["72c15da3.67bcb4","d0ebe41a.dbc338","d0c5c476.41e9f8","9394e281.e1baa","3ebe8a6.c2cc776","fd55653d.254eb8"]]},{"id":"72c15da3.67bcb4","type":"debug","z":"88029ce.abbab6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":660,"y":520,"wires":[]},{"id":"d0ebe41a.dbc338","type":"debug","z":"88029ce.abbab6","name":"Fixed Daily Charges","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.data.staticPrices.E1TOU.totalDailyPrice","targetType":"msg","statusVal":"","statusType":"auto","x":700,"y":580,"wires":[]},{"id":"d0c5c476.41e9f8","type":"debug","z":"88029ce.abbab6","name":"Peak KWH Price","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.data.staticPrices.E1TOU.networkPeakKWHPrice","targetType":"msg","statusVal":"","statusType":"auto","x":690,"y":620,"wires":[]},{"id":"3ebe8a6.c2cc776","type":"debug","z":"88029ce.abbab6","name":"Off Peak KWH Price","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.data.staticPrices.E1TOU.networkOffpeakKWHPrice","targetType":"msg","statusVal":"","statusType":"auto","x":700,"y":700,"wires":[]},{"id":"9394e281.e1baa","type":"debug","z":"88029ce.abbab6","name":"Shoulder KWH Price","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.data.staticPrices.E1TOU.networkShoulderKWHPrice","targetType":"msg","statusVal":"","statusType":"auto","x":700,"y":660,"wires":[]},{"id":"fd55653d.254eb8","type":"change","z":"88029ce.abbab6","name":"","rules":[{"t":"set","p":"ambertest","pt":"global","to":"payload.data.variablePricesAndRenewables","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":850,"y":460,"wires":[[]]}]

Thanks

Craig

I think a function node using findIndex and slice are you best bet.

2 lines of code.

Yeah i always find i come back to those two line functions later and have to remind myself how they work !! Plus now my son is getting into this and being a teenager i know he will not document any of this

But time to roll the sleeves up i guess !!

Thanks for taking the time to respond

Craig

Add comments :stuck_out_tongue_winking_eye:

You can use JSONata in a change node

payload.data.variablePricesAndRenewables[periodType = "FORECAST"][[0..19]]

this will return first 20 items where field = FORECAST

HA HA !!!

There is always one in every room!!

Craig

WOW !!

This JSONATA stuff is so powerful but it scares me to death !

Can you point me to a good beginner resource that i can work through to gt a handle on it ?

Craig

Good is a subjective term
here's where I go

and here is their exerciser, where you can add objects and expressions and test
https://try.jsonata.org/

Good one thanks Man - can not believe how easy that one was (when you know how !)

Craig

I suggest getting fully competent with js first. Anything can be done in js, only certain things can be done with jsonata.

JSONata is one of those things that is great until it isn't. Some things are really simple to comprehend, some are simple to do and the rest takes longer than learning JavaScript from scratch :scream:

My rule of thumb is if I can work it out in a few minutes then I'll use it. Otherwise I'll use a function node.

Yep i hear both you and Colin - and was 1/2 way through (blundering) writing a function to do it, when the one line answer came in - to say i was impressed is a very big understatement !

Craig

I agree with Colin and Julian here Craig.

JSONata can be great however in my experience, the following logic comes into play...

  • If it takes more than a couple of minutes to write the JSONata, I revert to JS
  • If there are many rows (500+) or sorting involved, I revert to JS (in certain operations, JSONata can easily be 300 times slower than the JS equivalent - example)

Just be aware that JSONata is often a good choice but not always the right choice.

OK guys - i think you have me convinced on this one.

So i have a raw object (which is the return of a query) which has 144 elements in it - what i have done so far is the below

  1. Using JSONATA - broken it into two seperate objects - one of actual price readings i.e. in the past and right now and the second for forecasts (i.e. in the future)

What i would like to do is extract the last reading in the Actual price readings - which should have the price right now and then extract the first 10 objects of the Forecasts which should have the estimated prices for the next 5 hours

Here is where i am at now with this

[{"id":"6028717e.571d7","type":"inject","z":"f2b4db9d.841788","name":"Check Prices","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"300","topic":"","payload":"","payloadType":"date","x":150,"y":120,"wires":[["416043a5.94179c"]]},{"id":"416043a5.94179c","type":"function","z":"f2b4db9d.841788","name":"set headers and change Postcode here","func":"msg.headers = {};\nmsg.headers[\"Content-Type\"] = \"application/json\";\nmsg.payload = '{ \"postcode\":\"2069\" }';\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":260,"y":180,"wires":[["a2b6857.bc69078"]]},{"id":"a2b6857.bc69078","type":"http request","z":"f2b4db9d.841788","name":"Make a Request for Castle Cove (Ausgrid) Prices","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://api.amberelectric.com.au/prices/listprices","tls":"","persist":false,"proxy":"","authType":"","x":230,"y":240,"wires":[["72c15da3.67bcb4","d0ebe41a.dbc338","d0c5c476.41e9f8","9394e281.e1baa","3ebe8a6.c2cc776","aaf92a51.b006e8","b801daea.9ec648","a947460.7f6c2b8","e4e36325.1f8b4","a62cfe87.7ed48","fd6dbd85.9381f","7bd5378c.12d2e8","1415f681.65f289"]]},{"id":"72c15da3.67bcb4","type":"debug","z":"f2b4db9d.841788","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":560,"y":180,"wires":[]},{"id":"d0ebe41a.dbc338","type":"debug","z":"f2b4db9d.841788","name":"Fixed Daily Charges","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.data.staticPrices.E1TOU.totalDailyPrice","targetType":"msg","statusVal":"","statusType":"auto","x":600,"y":240,"wires":[]},{"id":"d0c5c476.41e9f8","type":"debug","z":"f2b4db9d.841788","name":"Peak KWH Price","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.data.staticPrices.E1TOU.networkPeakKWHPrice","targetType":"msg","statusVal":"","statusType":"auto","x":590,"y":400,"wires":[]},{"id":"3ebe8a6.c2cc776","type":"debug","z":"f2b4db9d.841788","name":"Off Peak KWH Price","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.data.staticPrices.E1TOU.networkOffpeakKWHPrice","targetType":"msg","statusVal":"","statusType":"auto","x":600,"y":560,"wires":[]},{"id":"9394e281.e1baa","type":"debug","z":"f2b4db9d.841788","name":"Shoulder KWH Price","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.data.staticPrices.E1TOU.networkShoulderKWHPrice","targetType":"msg","statusVal":"","statusType":"auto","x":600,"y":480,"wires":[]},{"id":"aaf92a51.b006e8","type":"change","z":"f2b4db9d.841788","name":"","rules":[{"t":"set","p":"amber.Peak_KWH_Price","pt":"global","to":"payload.data.staticPrices.E1TOU.networkPeakKWHPrice","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":440,"wires":[[]]},{"id":"b801daea.9ec648","type":"change","z":"f2b4db9d.841788","name":"","rules":[{"t":"set","p":"amber.Shoulder_KWH_Price","pt":"global","to":"payload.data.staticPrices.E1TOU.networkShoulderKWHPrice","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":520,"wires":[[]]},{"id":"a947460.7f6c2b8","type":"change","z":"f2b4db9d.841788","name":"","rules":[{"t":"set","p":"amber.OffPeak_KWH_Price","pt":"global","to":"payload.data.staticPrices.E1TOU.networkOffpeakKWHPrice","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":600,"wires":[[]]},{"id":"e4e36325.1f8b4","type":"change","z":"f2b4db9d.841788","name":"","rules":[{"t":"set","p":"amber.Total_Fixed_Daily_Charges","pt":"global","to":"payload.data.staticPrices.E1TOU.totalDailyPrice","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":670,"y":300,"wires":[[]]},{"id":"ba2d4b33.6e1368","type":"comment","z":"f2b4db9d.841788","name":"Set ToU Pricing","info":"","x":180,"y":300,"wires":[]},{"id":"a62cfe87.7ed48","type":"function","z":"f2b4db9d.841788","name":"Set Prices","func":"// Set all the fixed KWH prices (inc GST)\n\n\n// Carbon Neutral Cost\na = 0.11;\n\n// Environmental Certificate Cost\nb = 2.0361;\n\n// Market Charges\nc = 0.1595;\n\n// Price Protection Hedging\nd = 0.55;\n\nvar Static_KWH_Pricing = 1.04*(a + b + c + d);\nvar CurrentTOUPrice = 1 ;\n\nglobal.set('amber.Static_KWH_Pricing',Static_KWH_Pricing);\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":170,"y":440,"wires":[[]]},{"id":"7bd5378c.12d2e8","type":"change","z":"f2b4db9d.841788","name":"","rules":[{"t":"set","p":"ambertest","pt":"global","to":"payload.data.variablePricesAndRenewables","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":960,"y":200,"wires":[[]]},{"id":"fd6dbd85.9381f","type":"change","z":"f2b4db9d.841788","name":"","rules":[{"t":"set","p":"AmberEstimatePriceObject","pt":"global","to":"payload.data.variablePricesAndRenewables[periodType = \"FORECAST\"][[0..19]]","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1010,"y":160,"wires":[[]]},{"id":"1415f681.65f289","type":"change","z":"f2b4db9d.841788","name":"","rules":[{"t":"set","p":"AmberActualPriceObject","pt":"global","to":"payload.data.variablePricesAndRenewables[periodType = \"ACTUAL\"][[0..50]]","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1000,"y":240,"wires":[["1b2208a5.6dd677"]]},{"id":"1b2208a5.6dd677","type":"debug","z":"f2b4db9d.841788","name":"Output 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1180,"y":340,"wires":[]}]

Am i going to be able to make this much cleaner and easier to read by moving it to a function or should i persist with the jsonata and a couple more change nodes ?

Craig

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