jsonata-js / jsonata

JSONata query and transformation language - http://jsonata.org
MIT License
2.03k stars 216 forks source link

$append returns non-array #501

Open BlitzInternet opened 3 years ago

BlitzInternet commented 3 years ago

Maybe the documentation is unclear here but I would expect a different result:

https://try.jsonata.org/BY5Z2PEQu

{
  "a": [
    {
      "id": 1
    },
    {
      "id": 3
    }
  ],
  "b": [
    {
      "id": 2
    }
  ]
}
(
    $mergeIns := function($new) {(
        $has := $filter(a, function($v){ $v.id = $new.id });
        $without := [$filter(a, function($v){ $v.id != $new.id })];
        $merged := $has ? $has : $new;
        $res := $append($wihout, $merged);
        $res
    )};
    {
        "res": $mergeIns(b[0])
    }
)

Expected: { "res": [{ "id": 1},{"id":3},{"id":2}]}

Actual: { "res": { "id": 2 } } - no array, only the second one.

I've logged the input vars to $append and they are as expected on their own, but the result is not.

Edit: it works if $merged and $without arguments are swapped, which should definitely be a bug

andrew-coleman commented 3 years ago

I'm struggling a bit to understand what you are trying to achieve, but let me comment first on the title $append returns non-array. That's true - in fact the function returns a sequence rather than an array (see https://docs.jsonata.org/processing#sequences). So you're right, the documentation of this function is misleading. I suspect I wrote that before I'd documented the concept of the 'sequence' (which has always been central to JSONata and was derived from XPath/XQuery). I'll use this issue as a documentation bug.

Back to your expression, the reason it doesn't return { "res": [{ "id": 1},{"id":3},{"id":2}]} is because $has returns nothing (empty sequence), so the function just returns $new which is what you are seeing.

As a side note, you don't need to use the $filter function if you are just filtering based on property value. You can use the [...] syntax. I.e.: $has := $filter(a, function($v){ $v.id = $new.id }) can be simply written as: $has := a[id = $new.id]

BlitzInternet commented 3 years ago

The goal of this function is to merge somthing into an array. I've cut away the update transform and used an input where id=2 does not exist in a, but the principle is the same.

I think my other problem was caused by "$v.id != $new.id", that seems to not work. Thanks for the help.