How to optimize sending associativ array (filter payload)

#1

Hello,

I have this payload (for exemple) : payload : [[0,"300",0,0,0,0,0],[0,0,0,0,0,0,0]]
I would like to send : payload : {"0":{"1":300}}

Also if my payload will be : payload : [[0,"300",0,"500",0,0,0],[0,0,"200",0,0,0,0]]
My message will have to be payload : {"0":[{"1":300}, {"3":500}], "1":{"2":200}} or {"0":[[1,3],[300,500]], "1":[[2],[200]]} (second is more optimized ?)

Do you know how make this or with an other way using native fonction ?
Thank for your feedback

0 Likes

#2

Well, I don't know of any "native" function, but I generally like to use a JSONata expression to morph one structure into another -- I plugged your data into the jsonata exerciser site and developed this expression:

payload~>$map(function($arr, $ind) {
	(
    	$tmp := $map($arr, function($v, $i) {
        	{"index": $i, "value": $number($v)}
        });
        {
        	$string($ind): [
	            [$tmp[value > 0].index],
    	        [$tmp[value > 0].value]
            ]
        }
    )
})~>$merge()

The output seems to match your second (optimized) output style... if you put this into a change node,
just make sure to select the J: pulldown, click the three dots ... to open the edit panel, and paste the expression. There is even an expression "tester" tab where you can put your actual payload data and see how the output changes as you modify the expression:

Or you can simply import this node...

[{"id":"e496cac4.80f788","type":"change","z":"d59690cd.1ee8c","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload~>$map(function($arr, $ind) {\t\t(\t    \t$tmp := $map($arr, function($v, $i) {\t        \t{\"index\": $i, \"value\": $number($v)}\t        });\t        {\t        \t$string($ind): [\t\t            [$tmp[value > 0].index],\t    \t        [$tmp[value > 0].value]\t            ]\t        }\t    )\t})~>$merge()\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1560,"y":320,"wires":[[]]}]
1 Like

#3

Hello @shrickus,
Thank you for your reply.

It work, but for example :
[[0,300,0,500,0,0,0],[0,0,0,0,0,0,0]] ==> {"0":[[1,3],[300,500]],"1":[[],[]]}

Is it possible to remove the "1" attribute ?

Is it possible to do a generic function for all array with 2 / 3 sub level ?

I didn't know this programming method ...

0 Likes

#4

Theres a jsonata exerciser at http://try.jsonata.org
Where you can import your input data and have a play

0 Likes

#5

I alredy find & try... but i don't know jsonata :frowning:

0 Likes

#6

never a better time than now to start learning :grin:
Try google with 'jsonata tutorial'

0 Likes

#7

It's pretty easy, once you understand the syntax -- so "no" it's probably not possible to figure out for the casual observer... here's how I would solve it:

payload~>$map(
    function($arr, $ind) {
        (
            $tmp := $map(
                $arr,
                function($v, $i) {
                    $number($v) ?
                    {
                        "index": $i,
                        "value": $number($v)
                    }
                }
            );
            {
                $string($ind): $tmp[value > 0] ? [
                    [$tmp[value > 0].index],
                    [$tmp[value > 0].value]
                ]
            }
        )
    }
)~>$merge()

Notice the addition of the filter $tmp[value > 0] ? which only creates the output array IF there are any values greater than 0.

0 Likes

#8

Thank you @shrickus,
This syntax is not usual for me ...

I try this

`payload~>$map( function($arr, $ind) {
(
$tmp := $map( $arr, function($v, $i){ $number($v) ? { "index": $i, "value": $number($v) } });

    { $string($ind): $tmp[value > 0] ? $each( $tmp[value > 0], function($v, $i){ {$string($i):$v} }) }
)

})~>$merge()`

To do that : payload : {"0":[{"1":300}, {"3":500}], "1":{"2":200}} but that don't find matches :frowning:

In fact, after i would like to compare 2 payload to make a filter .. :exploding_head:

0 Likes