Filtering Arrays

How can I filter an array?

That is: I have an array of objects, and I want to keep only those that pass a test (in this case that some key equals some value).

I've tried splitting, switching and then joining but that doesn't work in the degenerate case where there are no matching items (when I would expect an array of zero length). Instead it just stops - presumably because the join has nothing to join.

Can you post an example flow (with example input)?

If this array is in a single message, have you thought of using a function node with array.filter?

@afelix yes I did, but I was actually trying to get away from coding in a function. But this might be the easiest and most appropriate way for now at least - but I can imagine it being a useful node/flow/feature to have eg for reporting.

If you don't post an example, it is hard to help.

@bakman2 that's fair. I'm trying to construct one that isolates the question and will post it if I'm successful.

Hi - not sure how you are filtering - but your filter can always trigger the join at the end of the sequence if necessary, which will give you your empty array - eg

[{"id":"e949193e.986c98","type":"inject","z":"adc578f5.614308","name":"","topic":"","payload":"[\"a\",\"b\",\"c\",\"d\"]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":560,"wires":[["66747dcf.11c094"]]},{"id":"66747dcf.11c094","type":"split","z":"adc578f5.614308","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":310,"y":560,"wires":[["f8e31478.505fd8","d76b872a.ad2158","cc55684c.d63998"]]},{"id":"8132e033.450a","type":"join","z":"adc578f5.614308","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"num","reduceFixup":"","x":610,"y":560,"wires":[["5648a962.c64588"]]},{"id":"5648a962.c64588","type":"debug","z":"adc578f5.614308","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":770,"y":560,"wires":[]},{"id":"f8e31478.505fd8","type":"function","z":"adc578f5.614308","name":"look for \"e\"","func":"\n\nif (msg.payload == \"e\") { node.send(msg); }\nif (msg.parts.index+1 == msg.parts.count) {\n    node.send({complete:true});\n}\nreturn null;","outputs":1,"noerr":0,"x":470,"y":560,"wires":[["8132e033.450a"]]}]

If you want to get away from a function then using the join node in reduce mode should be able to do it somehow - but will need some jsonata magic :slight_smile:

I usually use a "for" loop

I do not know if it will help but this is one more way to make filters

[{"id":"a41ddcf7.6feb4","type":"function","z":"a6ca8919.830c98","name":"Funcion Bucle FOR","func":"if( msg.i=== undefined ) msg.i = 0;\nif( msg.saved === undefined ) msg.saved = msg.payload;\nvar i=msg.i\n\nmsg.payload = msg.saved[ msg.i ];\n\nreturn msg;","outputs":1,"noerr":0,"x":550,"y":860,"wires":[["c354e57d.6fa4d8","5aa165c2.cdb54c"]]},{"id":"c354e57d.6fa4d8","type":"function","z":"a6ca8919.830c98","name":"msg.i ++","func":"if ( (msg.i += 1) < msg.saved.length ) return msg;\n","outputs":1,"noerr":0,"x":560,"y":900,"wires":[["a41ddcf7.6feb4"]]},{"id":"5aa165c2.cdb54c","type":"switch","z":"a6ca8919.830c98","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"a","vt":"str"},{"t":"eq","v":"e","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":770,"y":860,"wires":[["aa492251.fbb"],["aa492251.fbb"]]},{"id":"a022c554.d19518","type":"inject","z":"a6ca8919.830c98","name":"Inject ","topic":"","payload":"[\"a\",\"e\",\"i\",\"o\",\"u\"]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":210,"y":860,"wires":[["a41ddcf7.6feb4"]]},{"id":"aa492251.fbb","type":"join","z":"a6ca8919.830c98","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"2","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":930,"y":860,"wires":[["17c175ff.8861aa"]]},{"id":"17c175ff.8861aa","type":"debug","z":"a6ca8919.830c98","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1050,"y":860,"wires":[]}]

The "cleanest" way I know is to pass the array of objects to a change node, using a JSONata expression to filter only those that match the test. If you want to post some sample data, and a description of what test to use one each object, I can give you a more concrete example...

1 Like

Thank you all for the replies. Using the flow from @dceejay as a base this is what I was trying inititally:

[{"id":"de5e2812.901928","type":"inject","z":"87b395b1.644fe8","name":"","topic":"","payload":"[\"a\",\"b\",\"c\",\"d\"]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":300,"wires":[["cbfc31eb.46eb1"]]},{"id":"cbfc31eb.46eb1","type":"split","z":"87b395b1.644fe8","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":340,"y":300,"wires":[["11911d0c.a3fe83"]]},{"id":"d398db8c.a1f848","type":"join","z":"87b395b1.644fe8","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"num","reduceFixup":"","x":640,"y":300,"wires":[["34741e58.ed7c52"]]},{"id":"34741e58.ed7c52","type":"debug","z":"87b395b1.644fe8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":800,"y":300,"wires":[]},{"id":"11911d0c.a3fe83","type":"switch","z":"87b395b1.644fe8","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"e","vt":"str"}],"checkall":"true","repair":true,"outputs":1,"x":490,"y":300,"wires":[["d398db8c.a1f848"]]}]

This works when there is at least one item that matches, but fails to progress when no items match. I understand why.

Using array.filter via a function appears to be the cleanest way, if a little opaque:

[{"id":"4f931fac.82fd","type":"inject","z":"87b395b1.644fe8","name":"","topic":"","payload":"[\"a\",\"b\",\"c\",\"d\"]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":400,"wires":[["218f8dd.bcf6a72"]]},{"id":"570daf41.c5461","type":"debug","z":"87b395b1.644fe8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":780,"y":400,"wires":[]},{"id":"218f8dd.bcf6a72","type":"function","z":"87b395b1.644fe8","name":"","func":"function filter(item) {\n    return item == \"e\"; \n}\n\nmsg.payload = msg.payload.filter(filter);\nreturn msg;","outputs":1,"noerr":0,"x":450,"y":400,"wires":[["570daf41.c5461"]]}]