JSONata exception -- JSONata expression help please

I am at a loss why this JSONata is failing with the following error:'
Expected "}", got ":"

I am trying to prepare the JSON payload for a QuickBase API call:

This is not how I would have shaped this JSON but it is the 'contract'. I would not have used the value property but instead had a literal. The numbered properties relate to a field in a QuickBase table.

Note that flow.shipmentContents is an array of shipment lines:

{
   "to": "bvhw2455g",
   "data": [
       $map(
            flow.shipmentContents,
            function($v) {
               "8": {"value": $v.SALES_ORDER_ID & '-' $v.DOCUMENT_TYPE & '-' & $v.LINE_ID},
               "9": {"value": $v.LINE_TYPE},
               "11": {"value": $v.GTIN},
               "12": {"value": $v.ITEM_DESCRIPTION},
               "13": {"value": $v.ALT_DESCRIPTION},
               "14": {"value": $v.DESCRIPTION},
               "15": {"value": $v.QUANTITY_ORDERED - $v.QUANTITY_SHIPPED},
               "16": {"value": $v.QUANTITY_ORDERED},
               "22": {"value": flow.foreignKeyId}
            }
        )
    ],
   "fieldsToReturn": [
        1,
        2
    ]
}

Google Gemini suggested wrapping the inner mapped object with (), as well as the concatenation but that does not help:

{
   "to": "bvhw2455g",
   "data": [
       $map(
            flow.shipmentContents,
            function($v) {(
               "8": {"value": ($v.SALES_ORDER_ID & '-' $v.DOCUMENT_TYPE & '-' & $v.LINE_ID)},
               "9": {"value": $v.LINE_TYPE},
               "11": {"value": $v.GTIN},
               "12": {"value": $v.ITEM_DESCRIPTION},
               "13": {"value": $v.ALT_DESCRIPTION},
               "14": {"value": $v.DESCRIPTION},
               "15": {"value": $v.QUANTITY_ORDERED - $v.QUANTITY_SHIPPED},
               "16": {"value": $v.QUANTITY_ORDERED},
               "22": {"value": flow.foreignKeyId}
            )}
        )
    ],
   "fieldsToReturn": [
        1,
        2
    ]
}

Thoughts?
Please don't tell me to use JavaScript instead.

I added code blocks around your code to make the post readable.

This kind of statement always puzzles me.

  • There are over 13 million JS developers around the world (various articles)
  • By my crude reckoning (and some research), there are ~10k JSONata devs
  • JS is faster (often a by a magnitude) than JSONata, especially in larger payloads and array processing.
  • Node-RED has first class JS type checking, syntax help and support in the Monaco editor (JSONata support is a hand full of completions and syntax colourisation, shoe-horned in to the editor by me)
  • LLMS have far more knowledge of JS than JSONata

Anyhow, back to your question, I wish I could help, but I am not up to speed on JSONata (I use JS for anything more than simple strings or numbers) and the docs / examples / LLMs are not great either.

There are one or 2 JSONata wizards in the forum, I'm certain someone can assist.

Maybe try tweaking the title to entice them in (e.g. "Need help with JSONata expression" might work?)


EDIT

I also moved this to the General category (Developing Nodes is for developeing contrib nodes)

I asked chatgpt and it offered
.

GPT-OSS 120B

What’s wrong

  1. Missing commas between the key/value pairs inside the object that the $map callback returns.
  2. String‑concatenation syntax is wrong – you can’t mix & with a literal - without quoting the dash.
  3. The $map call must return an array of objects, so each object literal needs to be wrapped in { … }.
  4. In JSONata the object keys must be quoted when they are not simple identifiers (e.g., "8").

Fixed JSONata expression

jsonata

{
  "to": "bvhw2455g",
  "data": $map(
    flow.shipmentContents,
    function($v) {
      {
        "8":  {"value": $v.SALES_ORDER_ID & "-" & $v.DOCUMENT_TYPE & "-" & $v.LINE_ID},
        "9":  {"value": $v.LINE_TYPE},
        "11": {"value": $v.GTIN},
        "12": {"value": $v.ITEM_DESCRIPTION},
        "13": {"value": $v.ALT_DESCRIPTION},
        "14": {"value": $v.DESCRIPTION},
        "15": {"value": $v.QUANTITY_ORDERED - $v.QUANTITY_SHIPPED},
        "16": {"value": $v.QUANTITY_ORDERED},
        "22": {"value": flow.foreignKeyId}
      }
    }
  ),
  "fieldsToReturn": [1, 2]
}

I have no idea if that's any better, I'd have probably done it with javascript. :upside_down_face:

Hi Steve, thanks for that reply. Google Gemini did make this statement when I fed it the URL to this post.

A known issue exists with the JSONata parser implementation in Node-RED's Change node regarding multi-line object definitions within function bodies when an outer object wraps the entire expression. The recommended solution from the Node-RED community is to define the JSONata expression to return only the array directly, handling surrounding keys like "to" , "data" , and "fieldsToReturn" in a preceding template/function node or within the Node-RED flow structure itself.

I tried the template approach, but even this gave the same error. I suspect the value property is causing the parser to not parse.

[
   $map(
       flow.shipmentContents,
       function($v) {
           (
               "8": {
                   "value": (
                       $v.SALES_ORDER_ID & '-' $v.DOCUMENT_TYPE & '-' &
               $v.LINE_ID
                   )
           },
               "9": {"value": $v.LINE_TYPE},
               "11": {"value": $v.GTIN},
               "12": {"value": $v.ITEM_DESCRIPTION},
               "13": {"value": $v.ALT_DESCRIPTION},
               "14": {"value": $v.DESCRIPTION},
               "15": {
                   "value": (
                       $v.QUANTITY_ORDERED - $v.QUANTITY_SHIPPED
                   )
           },
               "16": {"value": $v.QUANTITY_ORDERED},
               "22": {"value": flow.foreignKeyId}
   )
       }
        )
    ]

ADMIN EDIT: Wrapped code in triple back ticks for readability and to prevent forum formatting messing it up

That means Javascript is probably next. :rofl:

That isn't a object defintion, the fix from @jbudd is:

i.e. the second '{' is the object definition, the first '{' is the function definition and then you'll have to add a return - it being a function:

flow.shipmentContents,
    function($v) {
      return {
        "8":  {"value":

would be my guess.

Plus 1 dev as JSONata-to-Erlang parser - so that would be really niche!

1 Like

Well, interesting the LLM produced similar but different 'corrections' Changing the from my single quote to double quote on my concatentation made not difference, but the double bracket approach that ChatGPT recommended {{ code }} versus the bracket - paren approach {( code )} that Gemini suggested did resolve the issue.

I DID ask Gemini to rewrite my JSONata into Javascript for the Change node and that actually worked pretty well, even offering parameter checks and proper flow.get calls:

// Retrieve the necessary data from the flow context (similar to JSONata's flow variable)
// Note: In a real Node-RED flow, ensure 'flow.shipmentContents' and 'flow.foreignKeyId'
// are correctly set in previous nodes and stored in the flow context.
const shipmentContents = flow.get('shipmentContents') || [];
const foreignKeyId = flow.get('foreignKeyId');

// Check if we have data to process
if (!Array.isArray(shipmentContents) || shipmentContents.length === 0 || !foreignKeyId) {
    // Optionally handle error or return early if data is missing
    node.warn("Missing or invalid shipment contents or foreign key ID in flow context.");
    return null; // Stop the flow here
}

// Generate the Quickbase payload data array using .map()
const dataArray = shipmentContents.map(item => {
    // Create the object for each record
    return {
        "8": { "value": `${item.SALES_ORDER_ID}-${item.DOCUMENT_TYPE}-${item.LINE_ID}` },
        "9": { "value": item.LINE_TYPE },
        "11": { "value": item.GTIN },
        "12": { "value": item.ITEM_DESCRIPTION },
        "13": { "value": item.ALT_DESCRIPTION },
        "14": { "value": item.DESCRIPTION },
        "15": { "value": item.QUANTITY_ORDERED - item.QUANTITY_SHIPPED },
        "16": { "value": item.QUANTITY_ORDERED },
        "22": { "value": foreignKeyId }
    };
});

// Assemble the final payload object which will be returned by the function node
msg.payload = {
    "to": "bvhw2455g",
    "data": dataArray,
    "fieldsToReturn": [
        1,
        2
    ]
};

// Return the message object with the newly constructed payload
return msg;
1 Like

Is this a context value or a msg var name?
is there any imput dat example to view?

context value .. it works.

Unfortunately, no data to share here. This is production data from a Dairy manufacturing plant that makes 10% of the butter for the entire USA.

In JSONata it would be $flowContext("shipmentContents")

So can you create a simple example of the input
a two element array.

OK good to know. I went the Javascript route for now.
@E1cid
Does that $flowContext imply a Javascript callout? Can $ be used to callout to my own Javascript functions to extend JSONata?

Chatgpt initially told me that flow.shipmentContents was invalid, it should be flow("shipmentContents") but in her 'corrected' jsonata she went back to the original.
When I questioned this she declared that flow.shipmentContents is perfectly OK. Maybe she was thinking of msg.flow.shipmentContents ...

Now I come to think of it, I don't believed she mentioned how smart I was to raise the question. Mutter mutter.

$flowContext() and $globalContext() is a node-red extension to JSONata for context vars, as is $moment() a JSONata extension for moment js.

IF Chatgpt sort counselling they would diagnose it a people pleaser.

And a deluded liar!