specimen
specimen

Reputation: 1765

How to update an element in an array using AQL in ArangoDB if it exists, and add if it doesn't

I'm struggeling with something that is perhaps very simple:

I have an array of objects, where each object is Date+Value.

Using AQL I want to add a new date+value object to the array if it does not have one, or update the value with a new value (adding to existing value) if there's already an object w. the same date in the array.

New objects will always have a newer date than existing, so the array should be sorted.

Example data:

Starting with

[[date:"2024-10-05",value:2},{[date:"2024-10-06",value:1}]

Adding for {date:"2024-10-07",value:2}, since there's no entry for that date, the resulting array should be:

[[date:"2024-10-05",value:2},{[date:"2024-10-06",value:1},[date:"2024-10-07",value:2}]

After that, again adding {date:"2024-10-07",value:2} should update that one, so 2 becomes 4:

[[date:"2024-10-05",value:2},{[date:"2024-10-06",value:1},[date:"2024-10-07",value:4}]

The values in the new object comes in as parameters @newDate, @valueAdd.

It is specifically the add-or-update thing that I find difficult to understand how to do with AQL. I'm going to do this for a lot of arrays, each vertice has such an array, but for simplicity I left this out, as that is just a loop within a loop.

Update - using object instead

Although I feel this isn't "correct" using date-strings as keys, I have this working alternative using an object instead of an array.

Instead of: [[date:"2024-10-05",value:2},{[date:"2024-10-06",value:1},[date:"2024-10-07",value:4}]

Use an object with date-strings as keys (since I don't want duplicates for the same day, in that case want to update): {"2024-10-05":2, "2024-10-06:1,"2024-10-07:4}

Then I can easily do

let x = HAS(MyObject,@today) ? MyObject[@today] : 0
let xx = MERGE(NOT_NULL(MyObject,{}), {@today: x+@add})
UPDATE MyVertice WITH {MyObject: xx} IN MyCollection

This will add/insert like expected.

The problem now becomes fetching the latest value. With an array I could just do theArray[-1] to get the latest, but with an object I need to find the "latest key", that is the highest date. Luckily ArangoDb has a function ATTRIBUTES which has a sort parameter ATTRIBUTES(document, removeSystemAttrs, sort) → strArray, and ISO-dates can be sorted alphabetically, so I can do:

let MyVertice = DOCUMENT("MyCollection/A")
// some NOT_NULL logic removed to keep short
let latestDate = ATTRIBUTES(MyVertice.MyObject, true, true)[-1]
return MERGE(MyVertice , {LatestValue:{[latestDate]: NOT_NULL(MyVertice.MyObject[latestDate],0)}})

Upvotes: 1

Views: 28

Answers (0)

Related Questions