Help with Join node please

I have two arrays, derived from scraping a web page.
eg ["Sydney", "Perth"] and [24, 33]
I need to join them to create an array of objects based on the topic and array element number
[{"location": "Sydney", "temperature": 24}, {"location": "Perth", "temperature": 33}]

[{"id":"6195c4d9beec1f9f","type":"inject","z":"864d3d22d52ad621","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"temperature","payload":"[24, 33]","payloadType":"json","x":150,"y":220,"wires":[["02fd63ee1b69d3f9"]]},{"id":"e065d4d1e7c0eb23","type":"inject","z":"864d3d22d52ad621","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"location","payload":"[\"Sydney\", \"Perth\"]","payloadType":"json","x":170,"y":180,"wires":[["02fd63ee1b69d3f9"]]},{"id":"02fd63ee1b69d3f9","type":"join","z":"864d3d22d52ad621","name":"","mode":"auto","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","useparts":false,"accumulate":true,"timeout":"","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":410,"y":220,"wires":[["e274243f93ae035d"]]},{"id":"e274243f93ae035d","type":"debug","z":"864d3d22d52ad621","name":"debug 15","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":560,"y":220,"wires":[]},{"id":"6b7a839f8188b374","type":"comment","z":"864d3d22d52ad621","name":"How to get [{\"location\": \"Sydney\", \"temperature\": 24},{\"location\": \"Perth\", \"temperature\": 33}]","info":"","x":370,"y":140,"wires":[]}]

I suspect this is a job for the "reduce sequence" mode?
There are some join node example flows but they don't help me here.

Chatgpt suggests a join node and a function but surely it's possible without a function?

[{"id":"1ac1ef8e2d69e5ca","type":"function","z":"864d3d22d52ad621","name":"function 12","func":"let arrA = msg.payload.location;\nlet arrB = msg.payload.temperature;\n\nlet result = [];\n\nfor (let i = 0; i < Math.min(arrA.length, arrB.length); i++) {\n    result.push({\n        AAA: arrA[i],\n        BBB: arrB[i]\n    });\n}\n\nmsg.payload = result;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":510,"y":220,"wires":[["e274243f93ae035d"]]},{"id":"02fd63ee1b69d3f9","type":"join","z":"864d3d22d52ad621","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","useparts":false,"accumulate":false,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":370,"y":220,"wires":[["1ac1ef8e2d69e5ca"]]}]

Perhaps, but I have never managed to get my head around it.

I think here, I would use a join to put both messages into the payload then a simple for loop in a function node.

Flow

[{"id":"e065d4d1e7c0eb23","type":"inject","z":"76a8eede6d0be0df","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"location","payload":"[\"Sydney\", \"Perth\"]","payloadType":"json","x":990,"y":520,"wires":[["02fd63ee1b69d3f9"]]},{"id":"02fd63ee1b69d3f9","type":"join","z":"76a8eede6d0be0df","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","useparts":false,"accumulate":true,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":1230,"y":560,"wires":[["b81ddba7b987a21f"]]},{"id":"6195c4d9beec1f9f","type":"inject","z":"76a8eede6d0be0df","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"temperature","payload":"[24, 33]","payloadType":"json","x":970,"y":560,"wires":[["02fd63ee1b69d3f9"]]},{"id":"b81ddba7b987a21f","type":"function","z":"76a8eede6d0be0df","name":"make array of objects","func":"const data = msg.payload\nconst locations = data.location\nconst temperatures = data.temperature\n\nconst result = locations.map((location, index) => {\n    return {\n        location: location,\n        temperature: temperatures[index]\n    }\n})\n\nmsg.payload = result\nreturn msg\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1430,"y":560,"wires":[["e274243f93ae035d"]]},{"id":"e274243f93ae035d","type":"debug","z":"76a8eede6d0be0df","name":"debug 15","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1460,"y":600,"wires":[]}]

Function code only

const data = msg.payload
const locations = data.location
const temperatures = data.temperature

const result = locations.map((location, index) => {
    return {
        location: location,
        temperature: temperatures[index]
    }
})

msg.payload = result
return msg

Thanks Steve.

Likewise!

[{"id":"e4a7b7c8f9d0a1b2","type":"inject","z":"9cd9fa2d0d2e7202","name":"Simulate Input Arrays","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"{\"locations\": [\"Sydney\", \"Perth\"], \"temperatures\": [24, 33]}","payloadType":"json","x":220,"y":400,"wires":[["c1d2e3f4a5b6c7d8"]]},{"id":"c1d2e3f4a5b6c7d8","type":"change","z":"9cd9fa2d0d2e7202","name":"Transform with JSONata","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.locations ~> $map(function($location, $index) {{    \"location\": $location,    \"temperature\": payload.temperatures[$index]}})","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":400,"wires":[["a9b8c7d6e5f4a3b2"]]},{"id":"a9b8c7d6e5f4a3b2","type":"debug","z":"9cd9fa2d0d2e7202","name":"Output Result","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":720,"y":400,"wires":[]}]

Google Gemini gave me this snippet, is this what is the requirement ?

Well Gemini skips the join node in favour of a single joined inject, but yes that works, and no function :grinning_face:

I'd still like to see it done with just the join node, if possible.

If you import the built in demo for join -> reduce the last flow is probably close to what you want - but, it requires JSONata so IMO, it is less readable, less maintainable (and probably slower).

with two individual inputs and a join node, with jsonata expressionin change node.

[{"id":"6bc3e805f8dcfdb4","type":"inject","z":"9cd9fa2d0d2e7202","name":"Inject Locations","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"locations","payload":"[\"Sydney\", \"Perth\"]","payloadType":"json","x":160,"y":540,"wires":[["2ceb835304c1d3fa"]]},{"id":"2ceb835304c1d3fa","type":"join","z":"9cd9fa2d0d2e7202","name":"Join Arrays","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"5","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":410,"y":580,"wires":[["17256ca53326521c"]]},{"id":"230d3d44dbf5919b","type":"inject","z":"9cd9fa2d0d2e7202","name":"Inject Temperatures","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.2,"topic":"temperatures","payload":"[24, 33]","payloadType":"json","x":160,"y":620,"wires":[["2ceb835304c1d3fa"]]},{"id":"17256ca53326521c","type":"change","z":"9cd9fa2d0d2e7202","name":"Transform with JSONata","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.locations ~> $map(function($location, $index) {{    \"location\": $location,    \"temperature\": payload.temperatures[$index]}})","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":660,"y":580,"wires":[["c546054dc85d54ad"]]},{"id":"c546054dc85d54ad","type":"debug","z":"9cd9fa2d0d2e7202","name":"Output Result","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":910,"y":580,"wires":[]}]

Well that's the example that made me think the reduce sequence option might work but a single string input confused me and I couldn't grasp the join node settings.

This assumes that you have 2 properties (locations and temperature) - note that you can also put 2 change nodes behind eachother where you populate both properties:

$map(locations, function($v, $i) {
  {
    "location": $v,
    "temperature": temperatures[$i]
  }
})

A reduce sequence requires msg.parts.
example

[{"id":"e065d4d1e7c0eb23","type":"inject","z":"d1395164b4eec73e","name":"","props":[{"p":"payload"},{"p":"parts","v":"{\"id\":1234,\"key\":\"location\",\"count\":2,\"index\":0,\"type\":\"object\"}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[\"Sydney\", \"Perth\"]","payloadType":"json","x":740,"y":2560,"wires":[["02fd63ee1b69d3f9"]]},{"id":"02fd63ee1b69d3f9","type":"join","z":"d1395164b4eec73e","name":"","mode":"reduce","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","useparts":false,"accumulate":true,"timeout":"","count":"","reduceRight":false,"reduceExp":"$merge([$A,{$$.parts.key:$$.payload}])","reduceInit":"{}","reduceInitType":"json","reduceFixup":"$A.location#$i.${$:$A.temperature[$i]}","x":1070,"y":2600,"wires":[["e274243f93ae035d"]]},{"id":"6195c4d9beec1f9f","type":"inject","z":"d1395164b4eec73e","name":"","props":[{"p":"payload"},{"p":"parts","v":"{\"id\":1234,\"key\":\"temperature\",\"count\":2,\"index\":1,\"type\":\"object\"}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[24, 33]","payloadType":"json","x":710,"y":2600,"wires":[["02fd63ee1b69d3f9"]]},{"id":"e274243f93ae035d","type":"debug","z":"d1395164b4eec73e","name":"debug 15","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1280,"y":2600,"wires":[]}]

Not the clearest method, may be clearer with join > split > change > join sequence.

@E1cid's example certainly does combine the inputs, but as an object, not an array of objects.

I think I need to consider if my web scraping should be modified to avoid getting two arrays in the first place, and if my hoped for array of objects is the right structure.

My mistake, try this as the fix up expression

$A.location#$i.{$:$A.temperature[$i]}
1 Like