How to update objects from an embedded array

Hi,

I have this schema: Board collection where the documents contain an embedded attribute: kpis array (an array of objects)

{
“ref”: Ref(Collection(“Board”), “12345678910”),
“ts”: 1672508341600000,
“data”: {
“description”: “test”,
“kpis”: [
{
“nameKey”: “Cogs”,
“nameLabel”: “cogs”,
“value”: 1000000,
“used”: true
},
{
“nameKey”: “Labor”,
“nameLabel”: “labor”,
“value”: 200000,
“used”: true
}]
}
}

I need to do a partial update on the Board to update the kpis array in this way:

  • if the kpi exists (by nameKey) the kpi value will be updated by adding the new value to the current value
  • if the kpi doesn’t exist in the kpis array, the kpi will be added to the array.

There are 2 options to implement this update operation:

  1. I create a custom gql mutation (updateBoardKpis mutation) that is mapped to an fql function that implements this complex update logic (from above)
  2. I do this logic in javascript and I send the final object to be updated in Fauna (using the partialUpdateBoard mutation)

I want to know what is your opinion of what could be the best approach.

The first approach implies writing a complex fql function that receives the boardId and a kpis array: inputKpis, smth like this:

UpdateBoardKpis(“12345678910”, [
{
“nameKey”: “Cogs”,
“nameLabel”: “cogs”,
“value”: 500,
“used”: true
},
{
“nameKey”: “Material”,
“nameLabel”: “material”,
“value”: 400,
“used”: true
}
])

Based on the existing functions in the fql language this could be implemented by creating a new kpis array with the following:

  1. filter the kpis that are in the board kpis array and are not in the input kpis array
  2. filter the kpis that are in the input kpis array and are not in the board kpis array
  3. get the kpis that are in both array and update the value by adding the values of the kpis

And this final kpis array should be used to update the board kpis (replacing the board kpis with the new created one from those 3 steps)
I think that this approach is rather complex, and too long which could be too hard to maintain in the future.
The second approach, doing it all in javascript is simpler and easier and could be easily maintained but it requires:

  • a fetch of the board object (req to Fauna: find query)
  • the composition of a new kpis array in js (simpler) and then
  • an update of the board (req to Fauna: update mutation).

What do you think is the best approach to use here? And if you suggest the first one, do you know an easier and simpler way to do the fql function: UpdateBoardKpis?

Thank you

Clearly, the best approach is the first one, creating a custom gql mutation and creating the UDF for it in Fauna using FQL.
The second approach requires 2 requests to Fauna but writing the fql function is more difficult.
But here it is, the implementation of the FQL function:

Query(
  Lambda(
    ["boardId", "inputKpis"],
    Let(
      {
        boardRef: Get(Ref(Collection("Board"), Var("boardId")))
      },
    Update(Select("ref", Var("boardRef")), {
      data: {
        kpis:Union(
          Map(
            Select(["data","kpis"],Var("boardRef")),
            Lambda(
              "kpi",
              Let(
                {
                  matchingKpi: Select(0,Filter(Var("inputKpis"), Lambda("inputKpi", Equals(Select("nameKey", Var("inputKpi")), Select("nameKey", Var("kpi"))))), "")
                },
                If(
                  Not(Equals(Var("matchingKpi"), "")),
                  Merge(Var("kpi"), {value: Add(Select("value", Var("kpi")), Select("value", Var("matchingKpi")))}),
                  Var("kpi")
                )
              )
            )),
            
              Filter(
                Var("inputKpis"),
                Lambda("inputKpi",
                Let(
                  {
                    nameKeys:  Map(
                      Select(["data","kpis"],  Var("boardRef")),
                      Lambda("kpi", Select("nameKey",Var("kpi")))
                      )
                  },
                  Not(ContainsValue(
                    Select("nameKey", Var("inputKpi")),
                    Var("nameKeys"))
                  )
                  )
                )
              )
            )
        }
    })
  )
  )
)

Cheers

1 Like