Reputation: 147
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:
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
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
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