Remove item from nested array

Hello.

I’ve a class Message that can have many reactions.
Furthermore, I would like to keep in that way if there’s a solution for it.

I have a UDF that will do the follow:
Add, update and remove reactions from a message

This is a message.

{
  "content": "This is a test from the API",
  "reactions": [
    {
      "type": "❤",
      "author": Ref(Collection("users"), "298396134854885895")
    },
    {
      "type": "👌",
      "author": Ref(Collection("users"), "298396134854885895")
    }
  ]
}

Using filter to get the user if it has post any reactions

reactionData: Select(['data', "reactions"], Get(Var("messageRef")), false),
reactionFilter: Filter(Var("reactions"), Lambda("reaction", Equals("author", CurrentIdentity())))

I expect from reactionFilter a return like this

{
 "type": "❤",
 "author": "Jhon"
}

I have that approach.
For updating or creating a new one.

returnedData:  
{
   type: Var("type"),
   author: CurrentIdentity()
}

But for removing the nested array, I’m lost.
How can I do it?

Much appreciated.

An array field cannot really be mutated in place. You have to read the whole array, change it, and update the original document with the new array.

To update in place, check this post out

To remove an item, you can Filter for the opposite of what you want to remove.

Let(
  {
    reactions: Select(["data", "reactions"], Get(Var("messageRef")), false),
    type: "❤",
    author: CurrentIdentity(),
    new_reactions: Filter(
      Var("reactions"),
      Lambda(
        "reaction", 
        Not(
          And(
            Equals(Select("type", Var("reaction")), Var("type")),
            Equals(Select("author", Var("reaction")), Var("author"))
          )
        )
      )
    )
  },
  Update(
    Var("messageRef"),
    {
      data: {
        reactions: Var("new_reactions")
      }
    }
  )
)

Warning about editing arrays and nested objects

Absolutely you can! Depending on the application, it may not be very scalable, so just watch out for some things.

Due to Fauna’s transactional and serialization guarantees you will get problems if many requests to write the same document happen at the same time. That is, those requests will time out because they cannot happen simultaneously.

If there is not a large enough user base to cause race conditions for write operations, then your approach will work fine. Or for example, there may be many MANY users, but the audience for any given message is small.

On the other hand, imagine a message with a lot of viewers, and they all want to “react” at the about the same time. That could queue up dozens or hundreds or thousands or requests to write the same document. Most of those requests will fail.

Alternative using separate collection

I hope the above answered your original question. If you want to keep discussing alternate ways to managing reactions then maybe a new forum topic would be a good place to do that. I’ll say this, though:

Consider the Fwitter (Twitter + Fauna) as an example. It’s pretty dense… but I want to focus in on one thing.

In order to track Likes, there is a separate collection (fweetstats) where each Document stores the like-status and the user that performed the action. This way, “reacting” is simply creating a document. Removing that reaction is deleting the document.

Also, as an optimization, the summary of Likes is stored in the “Fweet”. This adds a lot more complexity to the “liking” process, but helps make fetching the “feed” much more efficient. This optimization also reestablishes writing the message Document for each reaction, which still has the same problem. But at least the operation is down to incrementing and decrementing a field, which is much less complex than manipulating an unbounded array.

2 Likes

Thanks @ptpaterson

I’ve finally done it in the way you posted, I want to keep like this for the moment as it has a limit of 10 reactions, so I think it would be fine.

Now I have to do another UDF kind of, and I’m doing with the Fwitter approach.

Really appreciated.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.