AJDee
AJDee

Reputation: 147

Is it possible if I can get the last key (latest message) added from the realtime database?

I would like to get the last key (the latest message) from my realtime database but not sure how this can be achieved. I see from this link i need to get Last child of my firebase databse that I can use orderByKey().limitToLast(1) to get this but it looks like I need to specify the complete ref in order to achieve this. Is that correct? Or is it possible if I can orderByKey().limitToLast(1) on the val()? Or is there another way I can achieve this? Here is my messages structure in the database:

enter image description here

enter image description here

I have a timestamp child under each key as shown above which I thought I could query in order to extract the latest key but I really don't know how to do this. Can someone please help? Below is my code so far:

database().ref(`messages/`).once(`value`, snapshot => {
 if(snapshot.exists()) {
   snapshot.forEach(function (childSnapshot) {
      if(childSnapshot.key.includes(auth().currentUser.uid)) {
      console.log("show me the key: "+childSnapshot.key)

      //not working
      console.log("show last message: "+ JSON.stringify(childSnapshot.val().orderbyKey().limitToLast(1)))
      }
    })
  }
})

console.log(JSON.stringify(messages)) => [{"-MfqYBzbusp1Cljgxpan":{"unreadMessage":true,"user":{"name":"Mike","avatar":"xxxxxx","_id":"tFhmw5oQoPhk8nF2sx5rE5BFqw93"},"timestamp":1627634061437,"senderId":"tFhmw5oQoPhk8nF2sx5rE5BFqw93","notification":{"body":"Hey","title":"Project","imageUrl":"./assets/xxxxx.png"},"text":"Hey"}}]

console.log(JSON.stringify(unreadMsgs)) => []

Upvotes: 0

Views: 262

Answers (2)

Dharmaraj
Dharmaraj

Reputation: 50920

The orderByKey and limitToLast methods exists on a DatabaseReference and not on the value you fetch from the snapshot fetched earlier. It seems the parent key for all messages is of format userId1userId2. If you know this combination then you run your query this way.

const uidsKey = "uid1" + "uid2"
const query = database().ref(`messages/${uidsKey}`).orderByChild("timestamp").limitToLast(1)

query.once("value").then((snapshot) => {
  console.log(snapshot.val())
})

But it seems you are trying to get UIDs of others users who have chats with user1 and trying to real all nodes first. I won't recommend doing that as that might have issues with security rules and so on. Instead if you keep list of those UIDs somewhere else, it'll be better. But if you want to keep what you have right now, try this:

const userUID = auth().currentUser.uid

database().ref("messages/").once("value").then(async (msgSnapshot) => {
  const keys = Object.keys(msgSnapshot.val() || {})
  const userChatKeys = keys.filter(k => k.includes(userUID))
  //const otherUserIDs = userChatKeys.map(k => k.replace(userUID, ""))

  //userChatKeys will be chat IDs where current user is included
  //now follow the same steps mentioned in first code snippet
  const queries = userChatKeys.map(chat => database().ref(`messages/${chat}`).orderByChild("timestamp").limitToLast(1).once("value"))
  const lastMessagesSnap = await Promise.all(queries)
  
  const messages = lastMessagesSnap.map(m => Object.values(m.val())[0])) 
  console.log(`messages: ${messages}`)
  const unreadMsgs = messages.filter((msg) => msg.unreadMessage === true)
  console.log(unreadMsgs.length)
})

This will logs last message from each of user's chat.

Upvotes: 2

Frank van Puffelen
Frank van Puffelen

Reputation: 599706

Firebase Realtime Database queries work on a flat list of nodes. So if you have a specific path /messages/nodeid already, you can find the latest message under that, but you can't find the latest message across all of /messages.

Reading all messages from all chatrooms, just to find the latest message for each chatroom this user is in is really wasteful though. As you add more users to the app, you're driving up the bandwidth cost for them, and for yourself too.

I recommend keeping a separate node where you track the chat rooms for each user, as explained in my answer on Best way to manage Chat channels in Firebase. With such a node you can then easily determine just the chat rooms for the current user, and then load the latest message for each of them with something like:

database().ref(`user_chatrooms/${auth().currentUser.uid}`).once(`value`, indexSnapshot => {
  indexSnapshot.forEach((indexSnapshotChild) => {
    let chatroomId = indexSnapshotChild.key;
    let query = database().ref(`messages/${chatroomId}`).orderByChild("timestamp").limitToLast(1)
    query.once(`value`, (msgSnapshot) => {
      console.log(`Last message in ${chatroomId} was ${msgSnapshot.val().text}`);
    })
  }
})

Upvotes: 1

Related Questions