Cryptocurrency Exchange Array (searching, tabling, etc)

Hi there,

I' just started using Node and spent a week struggling to implement the following "basic" config - finally decided to ask for help :slight_smile:

Using the ccxt-api-v2 node I check several exchanges if a specific crypto-coin exists, and if it does, grab a few of its object elements. Then, (via a http request) initiate a transaction on one of them, while also sending data to UI table.

Initially I took the approach of specifying the coin in the payload msg sent to the api, which worked when the coin exists; however, when it doesn't, the "error " leads to loss of msg payload to reference in other node and all kinds of issues (that I was trying to address along the way but it was getting ugly).

I imagine the "right" approach is not to specify the coin to the api, but to generate the entire array and then search for it? Unfortunately this is where I hit the wall of the lacking basic JV skills (everything I could find online got me close but not to the needed outcome).

Screenshot 2021-12-22 130848

Here, the array, I am checking for payload.payload[i].currency_pair - if there is a match, need to grab payload.payload[670].change_percentage, etc.

THANKS IN ADVANCE FOR ANY HELP

P.S. I am grabbing a "similar object set" from each exchange and merging it into a single record/row in the table. Initially I had 4 paths (functions multiple inputs/outputs , 4 change nodes, etc) going into a join nod prior to the table. Seems like there should be a more elegant implementation.

here are a Javasript and a JSONata examples of how to search an array of objects. hope it helps.

[{"id":"c0e9b277.7d217","type":"inject","z":"c791cbc0.84f648","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[{\"currency_pair\":\"PLA_USDT\",\"change_percentage\":20},{\"currency_pair\":\"PLO_USDT\",\"change_percentage\":30}]","payloadType":"json","x":130,"y":1320,"wires":[["d9aee851.b2bd8","7eece020.e16708"]]},{"id":"d9aee851.b2bd8","type":"change","z":"c791cbc0.84f648","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"($found := $$.payload[currency_pair = \"PLA_USDT\"];\t$exists($found) ? $found.change_percentage : \"not found\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":1320,"wires":[["787bde20.22dbc8"]]},{"id":"7eece020.e16708","type":"function","z":"c791cbc0.84f648","name":"","func":"let search_string = \"PLA_USDT\";\nmsg.payload = msg.payload.find(obj => obj.currency_pair === search_string) || \"not found\";\nmsg.payload = (msg.payload !== \"not found\") ? msg.payload.change_percentage : msg.payload;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":300,"y":1360,"wires":[["787bde20.22dbc8"]]},{"id":"787bde20.22dbc8","type":"debug","z":"c791cbc0.84f648","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":640,"y":1340,"wires":[]}]

For others to help it would be best to post your flow or a simple example of it. And the data coming from your crypto node, in a copyable format Then maybe someone could see a more elegant way to join/search your returns.

Thank you so much. Your example works perfectly; unfortunately I haven't been able to integrate it into my config - i.e. properly passing the crypto coin names to the change node. The names are formatted differently for each exchange; in the previous config I was passing them via msg.payload to the api-nodes; now that's not necessary (although the nodes still need to get triggered), so I am trying use flow variables to access in the change-node - can't get it to work, I am guessing syntax is incorrect

($found := $$.payload.payload[currency_pair = $flow.get('g_coin')];
$exists($found) ? $found.change_percentage : "not found")

Here is the revised flow with nodes that I think will be needed?

[
    {
        "id": "19925c368c4d96ea",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "4da7c11af13cd77b",
        "type": "ccxt-api-v2",
        "z": "19925c368c4d96ea",
        "name": "Gate.io : get_tickers",
        "exchange": [
            "gateio"
        ],
        "allexchanges": false,
        "apitype": "customAPI",
        "customapitype": "public_spot",
        "api": "public_spot_get_tickers",
        "apiprivate": "false",
        "filtermarkets": "",
        "filtermarketsType": "str",
        "symbol": "",
        "symbolType": "str",
        "limit": "",
        "limitType": "num",
        "since": "",
        "sinceType": "datepick",
        "timeframe": "1m",
        "timeframeType": "timeframeList",
        "ordertype": "limit",
        "orderside": "buy",
        "amount": "",
        "amountType": "num",
        "orderprice": "",
        "orderpriceType": "num",
        "orderid": "",
        "orderidType": "str",
        "code": "",
        "address": "",
        "tag": "",
        "apisecrets": "",
        "apipayload": "",
        "apipayloadType": "none",
        "x": 670,
        "y": 540,
        "wires": [
            [
                "9bf204b4227002d0",
                "f0d8462b39e4fca7"
            ]
        ]
    },
    {
        "id": "a06002f4195586c6",
        "type": "function",
        "z": "19925c368c4d96ea",
        "name": "format",
        "func": "var coin=msg.payload.currency;\nvar exchange=msg.payload.exchange;\n\nflow.set(\"coin\", msg.payload.currency);\nflow.set(\"exchange\", exchange);\n\nmsgF={};\nmsgG={};\nmsgB={};\nmsgC={};\n\nmsgF.payload = coin + \"/USD\";\nmsgG.payload = coin + \"_USDT\";\nmsgB.payload = coin + \"USDT\";\nmsgC.payload = coin + \"-USD\";\n\nflow.set(\"g_coin\", msgG);\n\nreturn [msgF,msgG,msgB,msgC];",
        "outputs": 4,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 370,
        "y": 300,
        "wires": [
            [
                "437e6d9c91e565dd"
            ],
            [
                "4da7c11af13cd77b"
            ],
            [
                "1feedb90268d108a"
            ],
            [
                "27d81f8b5ae5b04d"
            ]
        ]
    },
    {
        "id": "bc38250ac4c16847",
        "type": "ui_table",
        "z": "19925c368c4d96ea",
        "group": "ac9222da755f2e54",
        "name": "TABLE",
        "order": 1,
        "width": "0",
        "height": "0",
        "columns": [
            {
                "field": "coin",
                "title": "coin",
                "width": "10px",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "exchange",
                "title": "listed",
                "width": "15px",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "f_coin",
                "title": "ftx",
                "width": "5px",
                "align": "left",
                "formatter": "color",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "payload.gate.g_coin",
                "title": "gate",
                "width": "5px",
                "align": "left",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "payload.binance.b_coin",
                "title": "binance",
                "width": "5px",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "c_coin",
                "title": "coinbase",
                "width": "5px",
                "align": "left",
                "formatter": "progress",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "price",
                "title": "price",
                "width": "5px",
                "align": "left",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "change",
                "title": "change",
                "width": "5px",
                "align": "left",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "time",
                "title": "time",
                "width": "10px",
                "align": "left",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            }
        ],
        "outputs": 0,
        "cts": false,
        "x": 1590,
        "y": 480,
        "wires": []
    },
    {
        "id": "21f4410c78d3927b",
        "type": "inject",
        "z": "19925c368c4d96ea",
        "name": "notification",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{\"type\":\"new_coin\",\"message\":\"ETC has been listed on Gate.io!\",\"currency\":\"ETC\",\"exchange\":\"Gate.io\"}",
        "payloadType": "json",
        "x": 200,
        "y": 380,
        "wires": [
            [
                "a06002f4195586c6"
            ]
        ]
    },
    {
        "id": "437e6d9c91e565dd",
        "type": "ccxt-api-v2",
        "z": "19925c368c4d96ea",
        "name": "FTX : get_markets",
        "exchange": [
            "ftx"
        ],
        "allexchanges": false,
        "apitype": "customAPI",
        "customapitype": "public",
        "api": "public_get_markets",
        "apiprivate": "false",
        "filtermarkets": "",
        "filtermarketsType": "str",
        "symbol": "",
        "symbolType": "str",
        "limit": "",
        "limitType": "num",
        "since": "",
        "sinceType": "datepick",
        "timeframe": "1m",
        "timeframeType": "timeframeList",
        "ordertype": "limit",
        "orderside": "buy",
        "amount": "",
        "amountType": "num",
        "orderprice": "",
        "orderpriceType": "num",
        "orderid": "",
        "orderidType": "str",
        "code": "",
        "address": "",
        "tag": "",
        "apisecrets": "",
        "apipayload": "",
        "apipayloadType": "none",
        "x": 660,
        "y": 500,
        "wires": [
            [
                "9bf204b4227002d0"
            ]
        ]
    },
    {
        "id": "1feedb90268d108a",
        "type": "ccxt-api-v2",
        "z": "19925c368c4d96ea",
        "name": "Binance : get_ticker",
        "exchange": [
            "binance"
        ],
        "allexchanges": false,
        "apitype": "customAPI",
        "customapitype": "public",
        "api": "public_get_ticker/24hr",
        "apiprivate": "false",
        "filtermarkets": "",
        "filtermarketsType": "str",
        "symbol": "",
        "symbolType": "str",
        "limit": "",
        "limitType": "num",
        "since": "",
        "sinceType": "datepick",
        "timeframe": "1m",
        "timeframeType": "timeframeList",
        "ordertype": "limit",
        "orderside": "buy",
        "amount": "",
        "amountType": "num",
        "orderprice": "",
        "orderpriceType": "num",
        "orderid": "",
        "orderidType": "str",
        "code": "",
        "address": "",
        "tag": "",
        "apisecrets": "",
        "apipayload": "",
        "apipayloadType": "none",
        "x": 670,
        "y": 580,
        "wires": [
            [
                "9bf204b4227002d0"
            ]
        ]
    },
    {
        "id": "27d81f8b5ae5b04d",
        "type": "ccxt-api-v2",
        "z": "19925c368c4d96ea",
        "name": "Coinbase: get_products",
        "exchange": [
            "coinbasepro"
        ],
        "allexchanges": false,
        "apitype": "customAPI",
        "customapitype": "public",
        "api": "public_get_products",
        "apiprivate": "false",
        "filtermarkets": "",
        "filtermarketsType": "str",
        "symbol": "",
        "symbolType": "str",
        "limit": "",
        "limitType": "num",
        "since": "",
        "sinceType": "datepick",
        "timeframe": "1m",
        "timeframeType": "timeframeList",
        "ordertype": "limit",
        "orderside": "buy",
        "amount": "",
        "amountType": "num",
        "orderprice": "",
        "orderpriceType": "num",
        "orderid": "",
        "orderidType": "str",
        "code": "",
        "address": "",
        "tag": "",
        "apisecrets": "",
        "apipayload": "",
        "apipayloadType": "none",
        "x": 670,
        "y": 620,
        "wires": [
            []
        ]
    },
    {
        "id": "9bf204b4227002d0",
        "type": "debug",
        "z": "19925c368c4d96ea",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1210,
        "y": 240,
        "wires": []
    },
    {
        "id": "f0d8462b39e4fca7",
        "type": "change",
        "z": "19925c368c4d96ea",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "($found := $$.payload.payload[currency_pair = $flow.get('g_coin')];\t$exists($found) ? $found.change_percentage : \"not found\")\t\t",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1040,
        "y": 540,
        "wires": [
            [
                "9bf204b4227002d0",
                "47a0bff56a4d9ccb",
                "5f6a554694a774c8"
            ]
        ]
    },
    {
        "id": "97d7c5d19198fbc8",
        "type": "change",
        "z": "19925c368c4d96ea",
        "name": "",
        "rules": [],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1030,
        "y": 580,
        "wires": [
            [
                "47a0bff56a4d9ccb",
                "5f6a554694a774c8"
            ]
        ]
    },
    {
        "id": "141e5946e8a9d14b",
        "type": "change",
        "z": "19925c368c4d96ea",
        "name": "",
        "rules": [],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1030,
        "y": 500,
        "wires": [
            [
                "47a0bff56a4d9ccb",
                "5f6a554694a774c8"
            ]
        ]
    },
    {
        "id": "08f7befbe227b0a0",
        "type": "change",
        "z": "19925c368c4d96ea",
        "name": "",
        "rules": [],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1030,
        "y": 620,
        "wires": [
            [
                "47a0bff56a4d9ccb"
            ]
        ]
    },
    {
        "id": "47a0bff56a4d9ccb",
        "type": "join",
        "z": "19925c368c4d96ea",
        "name": "",
        "mode": "custom",
        "build": "object",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": false,
        "timeout": "",
        "count": "4",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "num",
        "reduceFixup": "",
        "x": 1410,
        "y": 540,
        "wires": [
            [
                "bc38250ac4c16847"
            ]
        ]
    },
    {
        "id": "4d57a1eac2784f44",
        "type": "http request",
        "z": "19925c368c4d96ea",
        "name": "transaction",
        "method": "GET",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "senderr": false,
        "x": 1520,
        "y": 760,
        "wires": [
            []
        ]
    },
    {
        "id": "5f6a554694a774c8",
        "type": "function",
        "z": "19925c368c4d96ea",
        "name": "",
        "func": "\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1370,
        "y": 660,
        "wires": [
            [
                "4d57a1eac2784f44"
            ]
        ]
    },
    {
        "id": "ac9222da755f2e54",
        "type": "ui_group",
        "name": "Default",
        "tab": "d2e1eaa537051a95",
        "order": 1,
        "disp": true,
        "width": "6",
        "collapse": false,
        "className": ""
    },
    {
        "id": "d2e1eaa537051a95",
        "type": "ui_tab",
        "name": "Home",
        "icon": "dashboard",
        "disabled": false,
        "hidden": false
    }
]

$flow.get("blah") would be $flowContext("blah")
There is a inbuilt expression tester, and a list of functions
here


Example

[{"id":"f9d4e55a.1c426","type":"inject","z":"c791cbc0.84f648","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"exchange\":\"test\",\"payload\":[{\"currency_pair\":\"PLA_USDT\",\"change_percentage\":20,\"last\":2000},{\"currency_pair\":\"PLO_USDT\",\"change_percentage\":30,\"last\":3000}]}","payloadType":"json","x":110,"y":1460,"wires":[["8e4d799c.540b88"]]},{"id":"8e4d799c.540b88","type":"change","z":"c791cbc0.84f648","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"($found := $$.payload.payload[currency_pair = \"PLA_USDT\"];\t$exists($found) ? \t $found.${\"change_percentage\":change_percentage,\t \"last\": last,\t \"currency_pair\": currency_pair,\t \"exchange\": $$.payload.exchange} : \t\"not found\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":290,"y":1460,"wires":[["e56963d9.90a898"]]},{"id":"e56963d9.90a898","type":"debug","z":"c791cbc0.84f648","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":620,"y":1480,"wires":[]}]

Thank you. I was able to get the flow working all the way to a dashboard table.

One problem that I experienced is that when one API node encounters a type of error/issue that interrupts the flow of msg (like a "timeout" in pulling data from a particular exchange) everything halts - I imagine (one reason) because the JOIN node is waiting to get all of its parts.

[
    {
        "id": "19925c368c4d96ea",
        "type": "tab",
        "label": "CRYPTO",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "4da7c11af13cd77b",
        "type": "ccxt-api-v2",
        "z": "19925c368c4d96ea",
        "name": "Gate.io : get_tickers",
        "exchange": [
            "gateio"
        ],
        "allexchanges": false,
        "apitype": "customAPI",
        "customapitype": "public_spot",
        "api": "public_spot_get_tickers",
        "apiprivate": "false",
        "filtermarkets": "",
        "filtermarketsType": "str",
        "symbol": "",
        "symbolType": "str",
        "limit": "",
        "limitType": "num",
        "since": "",
        "sinceType": "datepick",
        "timeframe": "1m",
        "timeframeType": "timeframeList",
        "ordertype": "limit",
        "orderside": "buy",
        "amount": "",
        "amountType": "num",
        "orderprice": "",
        "orderpriceType": "num",
        "orderid": "",
        "orderidType": "str",
        "code": "",
        "address": "",
        "tag": "",
        "apisecrets": "",
        "apipayload": "",
        "apipayloadType": "none",
        "x": 430,
        "y": 240,
        "wires": [
            [
                "9eb6f69be4d296c5"
            ]
        ]
    },
    {
        "id": "a06002f4195586c6",
        "type": "function",
        "z": "19925c368c4d96ea",
        "name": "in",
        "func": "var l_coin=msg.payload.currency;\nvar listed=msg.payload.exchange;\n\nflow.set('listed', listed);\nflow.set('l_coin', l_coin);\nflow.set('f_coin', l_coin + '/USD');\nflow.set('g_coin', l_coin + '_USDT');\nflow.set('b_coin', l_coin + 'USDT');\nflow.set('c_coin', l_coin + '-USD');\n\nmsgF={};\nmsgG={};\nmsgB={};\nmsgC={};\nreturn [msgF,msgG,msgB,msgC];",
        "outputs": 4,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 170,
        "y": 260,
        "wires": [
            [
                "437e6d9c91e565dd"
            ],
            [
                "4da7c11af13cd77b"
            ],
            [
                "1feedb90268d108a"
            ],
            [
                "27d81f8b5ae5b04d"
            ]
        ]
    },
    {
        "id": "21f4410c78d3927b",
        "type": "inject",
        "z": "19925c368c4d96ea",
        "name": "alert",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{\"type\":\"new_coin\",\"message\":\"ETC has been listed on Gate.io!\",\"currency\":\"GALA\",\"exchange\":\"Gate.io\"}",
        "payloadType": "json",
        "x": 130,
        "y": 80,
        "wires": [
            [
                "a06002f4195586c6"
            ]
        ]
    },
    {
        "id": "437e6d9c91e565dd",
        "type": "ccxt-api-v2",
        "z": "19925c368c4d96ea",
        "name": "FTX : get_markets",
        "exchange": [
            "ftx"
        ],
        "allexchanges": false,
        "apitype": "customAPI",
        "customapitype": "public",
        "api": "public_get_markets",
        "apiprivate": "false",
        "filtermarkets": "",
        "filtermarketsType": "str",
        "symbol": "",
        "symbolType": "str",
        "limit": "",
        "limitType": "num",
        "since": "",
        "sinceType": "datepick",
        "timeframe": "1m",
        "timeframeType": "timeframeList",
        "ordertype": "limit",
        "orderside": "buy",
        "amount": "",
        "amountType": "num",
        "orderprice": "",
        "orderpriceType": "num",
        "orderid": "",
        "orderidType": "str",
        "code": "",
        "address": "",
        "tag": "",
        "apisecrets": "",
        "apipayload": "",
        "apipayloadType": "none",
        "x": 420,
        "y": 200,
        "wires": [
            [
                "ab9f942c4f2f0686"
            ]
        ]
    },
    {
        "id": "1feedb90268d108a",
        "type": "ccxt-api-v2",
        "z": "19925c368c4d96ea",
        "name": "Binance : get_ticker",
        "exchange": [
            "binanceus"
        ],
        "allexchanges": false,
        "apitype": "customAPI",
        "customapitype": "public",
        "api": "public_get_ticker/24hr",
        "apiprivate": "false",
        "filtermarkets": "",
        "filtermarketsType": "str",
        "symbol": "",
        "symbolType": "str",
        "limit": "",
        "limitType": "num",
        "since": "",
        "sinceType": "datepick",
        "timeframe": "1m",
        "timeframeType": "timeframeList",
        "ordertype": "limit",
        "orderside": "buy",
        "amount": "",
        "amountType": "num",
        "orderprice": "",
        "orderpriceType": "num",
        "orderid": "",
        "orderidType": "str",
        "code": "",
        "address": "",
        "tag": "",
        "apisecrets": "",
        "apipayload": "",
        "apipayloadType": "none",
        "x": 430,
        "y": 280,
        "wires": [
            [
                "d7998371671437b3"
            ]
        ]
    },
    {
        "id": "27d81f8b5ae5b04d",
        "type": "ccxt-api-v2",
        "z": "19925c368c4d96ea",
        "name": "Coinbase: get_products",
        "exchange": [
            "coinbasepro"
        ],
        "allexchanges": false,
        "apitype": "customAPI",
        "customapitype": "public",
        "api": "public_get_products",
        "apiprivate": "false",
        "filtermarkets": "",
        "filtermarketsType": "str",
        "symbol": "",
        "symbolType": "str",
        "limit": "",
        "limitType": "num",
        "since": "",
        "sinceType": "datepick",
        "timeframe": "1m",
        "timeframeType": "timeframeList",
        "ordertype": "limit",
        "orderside": "buy",
        "amount": "",
        "amountType": "num",
        "orderprice": "",
        "orderpriceType": "num",
        "orderid": "",
        "orderidType": "str",
        "code": "",
        "address": "",
        "tag": "",
        "apisecrets": "",
        "apipayload": "",
        "apipayloadType": "none",
        "x": 430,
        "y": 320,
        "wires": [
            [
                "9b879d220b86ac80"
            ]
        ]
    },
    {
        "id": "47a0bff56a4d9ccb",
        "type": "join",
        "z": "19925c368c4d96ea",
        "name": "",
        "mode": "custom",
        "build": "object",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": false,
        "timeout": "",
        "count": "4",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "num",
        "reduceFixup": "",
        "x": 890,
        "y": 260,
        "wires": [
            [
                "11e8d8d04f29951e"
            ]
        ]
    },
    {
        "id": "754311d56ac3585b",
        "type": "function",
        "z": "19925c368c4d96ea",
        "name": "out",
        "func": "msgTable  = {};\nmsgAction = {};\n\n\nvar listed = flow.get('listed');\nvar l_coin = flow.get('l_coin');\nvar price; var change; var f_coin; var g_coin; var b_coin; var c_coin; var id; var token; var coin;\n\n    if (msg.payload.ftx.price > 0) {\n        price = msg.payload.ftx.price;\n        change = (msg.payload.ftx.change * 100).toFixed(2);   \n        id = 739970400;\n        token = \"bae88628-4c8a-4176-a43b-a8dbd5f4f82d00\";\n        coin = msg.payload.ftx.coin;\n}   \n    else if (msg.payload.gate.price > 0) {\n         price = msg.payload.gate.price; \n         change = msg.payload.gate.change; \n         id = 739970400;\n         token = \"bae88628-4c8a-4176-a43b-a8dbd5f4f82d00\";\n         coin = msg.payload.gate.coin;\n}   \n    else if (msg.payload.binance.price > 0) {\n         price = msg.payload.binance.price; \n         change = msg.payload.binance.change;\n         id = 739970400;\n         token = \"bae88628-4c8a-4176-a43b-a8dbd5f4f82d00\";\n         coin = msg.payload.binance.coin;\n}\n\n\nif (msg.payload.ftx.price > 0) { f_coin = msg.payload.ftx.coin }\nif (msg.payload.gate.price > 0) { g_coin = msg.payload.gate.coin }\nif (msg.payload.binance.price > 0) { b_coin = msg.payload.binance.coin }\nc_coin = msg.payload.coinbase.coin;\n\n\nmsgTable.payload = { \"l_coin\": l_coin, \"listed\": listed, \"f_coin\": f_coin, \"g_coin\": g_coin, \"b_coin\": b_coin, \"c_coin\": c_coin, \"price\": price, \"change\": change, \"time\": msg.time };\n\nmsgAction = { \"message_type\": \"bot\", \"bot_id\": id, \"email_token\": token, \"delay_seconds\": \"0\", \"pair\": coin};\n\nreturn [msgTable,msgAction];",
        "outputs": 2,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1030,
        "y": 340,
        "wires": [
            [
                "05817e66364585d6"
            ],
            []
        ]
    },
    {
        "id": "ab9f942c4f2f0686",
        "type": "change",
        "z": "19925c368c4d96ea",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "ftx",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "($found := $$.payload.payload.result[name = $flowContext('f_coin')];\t$exists($found) ? \t $found.${\t \"change\":change24h,\t \"price\": last,\t \"coin\": name,\t \"exchange\": $$.payload.exchange} : \t\"not found\")\t",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "time",
                "pt": "msg",
                "to": "",
                "tot": "date"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 670,
        "y": 200,
        "wires": [
            [
                "47a0bff56a4d9ccb"
            ]
        ]
    },
    {
        "id": "d7998371671437b3",
        "type": "change",
        "z": "19925c368c4d96ea",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "($found := $$.payload.payload[symbol = $flowContext('b_coin')];\t$exists($found) ? \t $found.${\t \"change\":priceChangePercent,\t \"price\": lastPrice,\t \"coin\": symbol,\t \"exchange\": $$.payload.exchange} : \t0)\t\t",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "binance",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 670,
        "y": 280,
        "wires": [
            [
                "47a0bff56a4d9ccb"
            ]
        ]
    },
    {
        "id": "9b879d220b86ac80",
        "type": "change",
        "z": "19925c368c4d96ea",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "($found := $$.payload.payload[id = $flowContext('c_coin')];\t$exists($found) ? \t $found.${\t \"coin\": id,\t \"price\": null,\t \"change\": null,\t \"exchange\": $$.payload.exchange} : \t\"not found\")\t\t",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "coinbase",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 670,
        "y": 320,
        "wires": [
            [
                "47a0bff56a4d9ccb"
            ]
        ]
    },
    {
        "id": "11e8d8d04f29951e",
        "type": "moment",
        "z": "19925c368c4d96ea",
        "name": "time",
        "topic": "",
        "input": "",
        "inputType": "date",
        "inTz": "America/New_York",
        "adjAmount": 0,
        "adjType": "days",
        "adjDir": "add",
        "format": "MM[/]DD[  -  ]LTS",
        "locale": "C",
        "output": "time",
        "outputType": "msg",
        "outTz": "America/New_York",
        "x": 950,
        "y": 180,
        "wires": [
            [
                "754311d56ac3585b"
            ]
        ]
    },
    {
        "id": "b19403fafc4f81ab",
        "type": "ui_table",
        "z": "19925c368c4d96ea",
        "group": "be72bda40c2b3554",
        "name": "Listings",
        "order": 1,
        "width": "8",
        "height": "10",
        "columns": [
            {
                "field": "l_coin",
                "title": "Coin",
                "width": "8%",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "listed",
                "title": "Listed",
                "width": "15%",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "f_coin",
                "title": "FTX",
                "width": "10%",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "g_coin",
                "title": "Gate.io",
                "width": "10%",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "b_coin",
                "title": "Binance",
                "width": "10%",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "c_coin",
                "title": "Coinbase",
                "width": "10%",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "price",
                "title": "Price",
                "width": "10%",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "change",
                "title": "Change",
                "width": "10%",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            },
            {
                "field": "time",
                "title": "Timestamp",
                "width": "15%",
                "align": "center",
                "formatter": "plaintext",
                "formatterParams": {
                    "target": "_blank"
                }
            }
        ],
        "outputs": 1,
        "cts": true,
        "x": 1470,
        "y": 300,
        "wires": [
            []
        ]
    },
    {
        "id": "05817e66364585d6",
        "type": "function",
        "z": "19925c368c4d96ea",
        "name": "msg_events",
        "func": "var msg_obj = msg.payload ;\nvar arr_msgs = flow.get(\"msg_events\", 'memoryOnly');\n\nif (arr_msgs===undefined ) {\n    // Create an empty array if it does not exist yet\n    arr_msgs = [];\n    //arr_msgs.push(msg_obj) ; \n        if (msg_obj !== \"1\") {\n            arr_msgs.push(msg_obj);\n            flow.set(\"msg_events\",arr_msgs, 'memoryOnly');\n        }\n    \n//    return msg ;\n\n} else {\n        // This is a new user, save and return in the first port\n        if (msg_obj !== \"1\") {\n            arr_msgs.push(msg_obj);\n            flow.set(\"msg_events\",arr_msgs, 'memoryOnly');\n        }\n} \nmsg.payload = flow.get(\"msg_events\", 'memoryOnly');\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1120,
        "y": 240,
        "wires": [
            [
                "b6eb52354b96d980",
                "4af1cdb4a5ceb92c"
            ]
        ]
    },
    {
        "id": "98d0cecfaa18a8c8",
        "type": "function",
        "z": "19925c368c4d96ea",
        "name": "clear",
        "func": "var cfg = undefined ;\nflow.set('msg_events', cfg, 'memoryOnly');\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1350,
        "y": 380,
        "wires": [
            [
                "b19403fafc4f81ab"
            ]
        ]
    },
    {
        "id": "7e4d7d78076a8f33",
        "type": "inject",
        "z": "19925c368c4d96ea",
        "name": "clear",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "0.1",
        "topic": "",
        "payload": "1",
        "payloadType": "str",
        "x": 1230,
        "y": 380,
        "wires": [
            [
                "98d0cecfaa18a8c8"
            ]
        ]
    },
    {
        "id": "b6eb52354b96d980",
        "type": "delay",
        "z": "19925c368c4d96ea",
        "name": "1ms",
        "pauseType": "delay",
        "timeout": "1",
        "timeoutUnits": "milliseconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 1310,
        "y": 240,
        "wires": [
            [
                "b19403fafc4f81ab"
            ]
        ]
    },
    {
        "id": "4af1cdb4a5ceb92c",
        "type": "change",
        "z": "19925c368c4d96ea",
        "name": "refresh",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "[]",
                "tot": "json"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1290,
        "y": 300,
        "wires": [
            [
                "b19403fafc4f81ab"
            ]
        ]
    },
    {
        "id": "36265ea3b12c0c9b",
        "type": "http in",
        "z": "19925c368c4d96ea",
        "name": "Alert",
        "url": "/crypto-alert",
        "method": "post",
        "upload": false,
        "swaggerDoc": "",
        "x": 130,
        "y": 380,
        "wires": [
            [
                "3e2acd2032de1cd3",
                "a06002f4195586c6"
            ]
        ]
    },
    {
        "id": "3e2acd2032de1cd3",
        "type": "http response",
        "z": "19925c368c4d96ea",
        "name": "OK",
        "statusCode": "200",
        "headers": {},
        "x": 130,
        "y": 480,
        "wires": []
    },
    {
        "id": "9eb6f69be4d296c5",
        "type": "change",
        "z": "19925c368c4d96ea",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "gate",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "($found := $$.payload.payload[currency_pair = $flowContext('g_coin')];\t$exists($found) ? \t $found.${\t \"change\":change_percentage,\t \"price\": last,\t \"coin\": currency_pair,\t \"exchange\": $$.payload.exchange} : \t\"not found\")\t",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "time",
                "pt": "msg",
                "to": "",
                "tot": "date"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 670,
        "y": 240,
        "wires": [
            []
        ]
    },
    {
        "id": "be72bda40c2b3554",
        "type": "ui_group",
        "name": "Alerts",
        "tab": "7e13e6107768d821",
        "order": 2,
        "disp": false,
        "width": "8",
        "collapse": false,
        "className": ""
    },
    {
        "id": "7e13e6107768d821",
        "type": "ui_tab",
        "name": "CRYPTO",
        "icon": "dashboard",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]

Could you not add a time out to your join node?

Oh, didn't see that :slight_smile: So after the timeout it will send through a "partial" message? Should I do modify something in the OUT function which organized/distributes the data from the JOIN node to the table, charts (I know the OUT function could be improved to be more robust)

msgTable  = {};
msgChart  = {};
msgAction = {};


var listed = flow.get('listed');
var l_coin = flow.get('l_coin');
var price; var change; var f_coin; var g_coin; var b_coin; var c_coin; var id; var token; var coin; var symbol;

    if (msg.payload.ftx.price > 0) {
        price = msg.payload.ftx.price;
        change = (msg.payload.ftx.change * 100).toFixed(2);   
        id = 739970400;
        token = "bae88628-4c8a-4176-a43b-a8dbd5f4f82d00";
        coin = msg.payload.ftx.coin;
        symbol = "FTX:"+ l_coin + "USD";
}   
    else if (msg.payload.gate.price > 0) {
         price = msg.payload.gate.price; 
         change = msg.payload.gate.change; 
         id = 739970400;
         token = "bae88628-4c8a-4176-a43b-a8dbd5f4f82d00";
         coin = msg.payload.gate.coin;
         symbol = "KUCOIN:"+ l_coin + "USD";
}   
    else if (msg.payload.binance.price > 0) {
         price = msg.payload.binance.price; 
         change = msg.payload.binance.change;
         id = 739970400;
         token = "bae88628-4c8a-4176-a43b-a8dbd5f4f82d00";
         coin = msg.payload.binance.coin;
         symbol = "BINANCE:"+ l_coin + "USDT";
}


if (msg.payload.ftx.price > 0) { f_coin = msg.payload.ftx.coin }
if (msg.payload.gate.price > 0) { g_coin = msg.payload.gate.coin }
if (msg.payload.binance.price > 0) { b_coin = msg.payload.binance.coin }
c_coin = msg.payload.coinbase.coin;


msgTable.payload = { "l_coin": l_coin, "listed": listed, "f_coin": f_coin, "g_coin": g_coin, "b_coin": b_coin, "c_coin": c_coin, "price": price, "change": change, "time": msg.time };
msgChart.payload = symbol;
msgAction = { "message_type": "bot", "bot_id": id, "email_token": token, "delay_seconds": "0", "pair": coin};

return [msgTable,msgChart,msgAction];

Hello again! I am struggling to figure out how to grab price data point from one of the api arrays using your approach.

($found := $$.payload.payload[$flowContext('BICO-USD')];
$exists($found) ?
$found.${
"price": $$.payload.payload,
"exchange": $$.payload.exchange}
:
"not found")

The structure is different from the others, in not having a variable name associated with the value). The prices would be:

payload.payload["BICO-USD"][0][1]

payload.payload["IMX-USDT"][0][1]

Thank you!

The property "BICO-USD" has a "-" in it which is a nonstandard char, not allowed in a dot notaion property name so the property name would have to be in ` `.
As with thids example

[{"id":"c0e9b277.7d217","type":"inject","z":"c791cbc0.84f648","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"payload\":{\"BICO-USD\":[[11111111,4.2,3],[2222222,5.3,3]],\"IMX-USDT\":[[11111111,6.2,3],[2222222,7.3,3]]}}","payloadType":"json","x":110,"y":2240,"wires":[["3076a1e6.4b45a6"]]},{"id":"3076a1e6.4b45a6","type":"change","z":"c791cbc0.84f648","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"(\t   $found := $$.payload.payload.`BICO-USD`;\t   $exists($found) ? {\"price\": $found[0][1]}: \"not found\"\t)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":2240,"wires":[["787bde20.22dbc8"]]},{"id":"787bde20.22dbc8","type":"debug","z":"c791cbc0.84f648","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":620,"y":2260,"wires":[]}]
(
   $found := $$.payload.payload.`BICO-USD`;
   $exists($found) ? {"price": $found[0][1]}: "not found"
)
/* Or use $lookup()*/
(
   $found := $$.payload.payload.$lookup($, "BICO-USD");
   $exists($found) ? {"price": $found[0][1]}: "not found"
)

so to access the value direct in JSONata it would be

payload.payload.`BICO-USD`[0][1]

p.s. could you please enclose all code and json's in triple back ticks
e.g.
```
code
```
Also images of data are not copyable, It would be better to copy the objects and paste between backticks, then others have easy access to test with your data.

Hi, it works with the symbol specified directly; can't get the variable version right. Any advantages in using $lookup?

($found := $$.payload.payload.($flowContext('c_coin'));
$exists($found) ? 
 $found.${
 "price": $found[0][1],
 "exchange": $$.payload.exchange} 
 : 
"not found")


would be better using lookup()

[{"id":"c0e9b277.7d217","type":"inject","z":"c791cbc0.84f648","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"exchange\":\"test\",\"payload\":{\"BICO-USD\":[[1640631600,5.35,5.39,5.38,5.38],[1640628000,5.31,5.42,5.4,5.39],[1640624400,5.28,5.46,5.43,5.42]],\"IMX-USDT\":[[1640631600,5.44,5.45,5.44,5.45],[1640628000,5.37,5.49,5.43,5.44],[1640624400,5.15,5.44,5.15,5.44]],\"BLZ-USD\":[[1640631600,0.2566,0.2572,0.257,0.2566],[1640628000,0.2559,0.2586,0.2584,0.2567],[1640624400,0.2544,0.2594,0.2544,0.2579]],\"SUPER-USD\":[[1640631600,1.36,1.37,1.37,1.36],[1640628000,1.36,1.38,1.38,1.37],[1640624400,1.37,1.44,1.39,1.38]],\"MCO2-USD\":[[1640631600,10.58,10.65,10.58,10.65],[1640628000,10.5,10.63,10.51,10.57],[1640624400,10.46,10.68,10.67,10.54]],\"MCO2-USDT\":[[1640631600,10.6,10.61,10.6,10.61],[1640628000,10.54,10.59,10.54,10.59],[1640624400,10.5,10.65,10.65,10.5]]}}","payloadType":"json","x":110,"y":2240,"wires":[["3076a1e6.4b45a6"]]},{"id":"3076a1e6.4b45a6","type":"change","z":"c791cbc0.84f648","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"(\t   $found := $$.payload.payload.$lookup($, $flowContext(\"c_coin\"));\t   $exists($found) ? \t   {\t       \"price\": $found[0][1],\t       \"exchange\": $$.payload.exchange\t   }: \"not found\"\t)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":2240,"wires":[["787bde20.22dbc8"]]},{"id":"787bde20.22dbc8","type":"debug","z":"c791cbc0.84f648","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":620,"y":2260,"wires":[]}]

expression

(
   $found := $$.payload.payload.$lookup($, $flowContext("c_coin"));
   $exists($found) ? 
   {
       "price": $found[0][1],
       "exchange": $$.payload.exchange
   }: "not found"
)

I just noticed noticed this reply - but you're still testing the data (seem like the threads got spilt up)

If you don't mind a brief explanation, why the $lookup approach preferable?

Reason from post 11.
The result of the flow context still contains an illegal character for dot notation.

Ok, that works, thank you so much for your help and time! I think I mentioned that in this case I want to use an includes("xxx") type method to catch base-pair variations (GALA-USD, GAL-USDT, etc) - how can I specify that?

with the data from last example
try something like this

["IMX-USDT","BICO-USD"].$lookup($$.payload.payload, $)[0][1]

Sorry, I don't understand how the function I am currently using gets modified?
"l_coin" is the coin component (BICO)
" c_coin" is pre-formatted BICO-USD
Now I also want to check for existence of BICO-USDT

Perhaps there is no need to pre-format "l_coin" ... it can be used directly in the function along with USD/USDT strings.

(
$found := $$.payload.payload.$lookup($, $flowContext("c_coin"));
$exists($found) ?
{
"price": $found[0][1],
"exchange": $$.payload.exchange
}: "not found"
)

I not following you. Maybe explain what the input will be and what output you require and in what format.

The initial flow input is the name of the coin: "XXX" ("l_coin" variable). Then I am using the following change function to check for existence of "XXX-USD" (represented by "c_coin", the formatted version of the variable ). Now I want to check for existence of both XXX-USD and XXX-USDT. So I can create another formatted variable (c_coin_2nd_format) and use them together in the function, or (preferably) use "l_coin" (which is XXX) along with "USD" and "USDT" strings in the function to check for existence of both.

(
$found := $$.payload.payload.$lookup($, $flowContext("c_coin"));
$exists($found) ?
{
"price": $found[0][1],
"exchange": $$.payload.exchange
}: "not found"
)
[/quote]