0

Here i'm working in a chat application, i want to maintain the unread count for the recipient side. My json structre in console looks like

user_history
|
|--> user_a_uuid
    |-> last_msg
    |-> last_msg_timestamp
    |-> unread_count

the scope of this question is, how to increment the value of unread_count. Prior incrementing i have the user_a_uuid and the node user_history & unread_count as a constant. So i tried as follows

dbRef.child("user_history")
     .child(user_a_uuid)
     .child("unread_count")
     .runTransactionBlock { (unreadCount) -> TransactionResult in 
        var value = unreadCount.value as? Int

        if value == nil {
            value = 0
        }

        unreadCount.value = value! + 1
        return TransactionResult.success(withValue: unreadCount)
}

Actually to be precise i borrowed this solution from here. I also tried to follow the doc. But the thing is that, i don't want to run transaction on the root node as in the doc. I want to run the transaction only on the unread_count doc.

Problem I'm facing:

After attempting this code, the problem i face is that, unread_count node getting deleted as soon and while i return the TransactionResult inside the completion block, it added unread_count. The problem is that the value is not incremented due to unread_count getting deleted. It always stays to 1.

Thanks in advance.

Community
  • 1
  • 1
Ratul Sharker
  • 7,484
  • 4
  • 35
  • 44

1 Answers1

1

It appears you want to increment a counter stored in a node without affecting the other items in the node. Based on the information in the question there doesn't appear to be a need to use a transaction block in this use case due to the count being stored in code.

Prior incrementing i have the user_a_uuid and the node user_history & unread_count as a constant

I believe this means you're storing unread_count in a variable in code so if that's correct, it simply needs to be incremented in code and written to the node.

Starting with a duplicate structure:

user_history
   uid_0
      last_msg: "some message"
      last_msg_timestamp: "20181028075700"
      unread_count: 2

and now we've added another message. The var needs to be incremented and then the corresponding node in Firebase need to be updated with the new value. Here's the code that does that:

func updateMsgCount() { 
   self.unread_count += 1 //this is a class var or however it's stored in code
   let unreadCountRef =  self.ref.child("user_history").child("uid_0").child("unread_count")
   unreadCountRef.setValue(self.unread_count)

Suppose however, that the unread_count is not stored in code but only stored in Firebase. Here's the code to read in the unread_count node, increment the count and store it back in Firebase.

func updateCount() {
   let unreadCountRef = self.ref.child("user_history").child("uid_0").child("unread_count")
   unreadCountRef.observeSingleEvent(of: .value, with: { snapshot in
      var currentCount = snapshot.value as? Int ?? 0
      currentCount += 1
      unreadCountRef.setValue(currentCount)
   })
}

If you really need a transaction block, here's one to accomplish the same thing

func updateCountTransactionStyle() {
    let unreadCountRef = self.ref.child("user_history").child("uid_0").child("unread_count")
    unreadCountRef.runTransactionBlock( { (currentData: MutableData) -> TransactionResult in

        var currentCount = currentData.value as? Int ?? 0
        currentCount += 1
        currentData.value = currentCount

        return TransactionResult.success(withValue: currentData)
    })
}
Jay
  • 34,438
  • 18
  • 52
  • 81
  • Thanks for your effort. Actually i'm not maintaining the `unread_count` within a variable, i just needed to read it on the recipient side and show as a badge. The reason is that, the transaction is being used here that an user can login from multiple device, though it is not practical to send message from multiple devices simultaneously, but i added this in case of occurrence such event. The last block you shared actually the same thing i've asked with shorter version. – Ratul Sharker Oct 28 '18 at 14:07
  • I found the bug in my code, where is set the whole dictionary of `last_message`, `last_msg_timestamp` and `unread_count`. This writing of whole dictionary erases the `unread_count`. The solution was to iterate through each key in the dictionary `allKeys` and write them one by one on the node. – Ratul Sharker Oct 28 '18 at 14:10
  • @RatulSharker Glad you discovered the issue! I hope my answer helped as I think it is a solution to your question, even if there was a separate issue. If it helped or provided direction, please accept it so it can help others. I don't think iterating through nodes is the best solution though. You should be able to just read in the unread_count, increment it and write it back out without erasing the other values, as you can see from both of my examples. – Jay Oct 28 '18 at 14:30
  • The case i'm bound to iterate over the dictionary because, sender side set this values and receiver side meant to set it to zero while the receiver enter the message details view. In your suggestion `last_message`, `last_message_timestamp` and `unread_count` needed to be read first before writing the dictionary into that node. Which seems more task and reading and writing the `unread_count` may create a bug while sender incrementing it and receiver set it to zero, so could not let the increment operation outside of the transaction. – Ratul Sharker Oct 28 '18 at 14:38