javascripthtmlfirebasefirebase-realtime-database

Messages are not ordering correctly in Firebase


I created firebase website using JS and frontend.

Eveything works correctly expect this one thing. My chats are not ordering by date correctly.I want them to order in chronological order, so the older messages are on top.

My JSON snippet

"messages": {
    "-O70WTtDPs8et5-zRVV4": {
      "message": "Hello!",
      "senderId": "UJA4AVrSSdZGOJc0bXYbxOcLOB22",
      "timestamp": 1726602407195
    },
    "-O70WW1AMJk4mJHBZuaY": {
      "message": "Hey",
      "senderId": "nKHb1krQokcFdo5VcDusaaj9TLl1",
      "timestamp": 1726602415953
    },
    "-O70WYXD2x6cNmQJAg2n": {
      "message": "How are you?",
      "senderId": "UJA4AVrSSdZGOJc0bXYbxOcLOB22",
      "timestamp": 1726602426203
    },
    "-O70WbhflR-FBuYtvcNn": {
      "message": "Good, thanks !",
      "senderId": "nKHb1krQokcFdo5VcDusaaj9TLl1",
      "timestamp": 1726602443313
    },
    "-O70X0TNMogcRrGyKYiJ": {
      "message": "Can I exchange X",
      "senderId": "UJA4AVrSSdZGOJc0bXYbxOcLOB22",
      "timestamp": 1726602548834
    },
    "-O70X2GLfa2aKc1KOV-C": {
      "message": "Yep",
      "senderId": "nKHb1krQokcFdo5VcDusaaj9TLl1",
      "timestamp": 1726602556185
    },
    "-O70hzi8OgVY6eRybn3D": {
      "message": "Hallo",
      "senderId": "UJA4AVrSSdZGOJc0bXYbxOcLOB22",
      "timestamp": 1726605687282
    }
  }

This is what i see now:

What I want to see:

So even though User2 texted first when logged in as User1 I see first mt messages and only then User2 messages

My code

document.addEventListener("DOMContentLoaded", () => {
  firebase.auth().onAuthStateChanged((user) => {
    if (user) {
      const chatId = new URLSearchParams(window.location.search).get("chatId");
      if (!chatId) {
        console.error("Invalid or missing chatId in URL.");
        return;
      }

      // Retrieve messages ordered by timestamp
      const messagesRefForDisplay = firebase
        .database()
        .ref(`chats/${chatId}/messages`)
        .orderByChild("timestamp");
      // Use a regular reference for sending messages
      const messagesRefForSending = firebase
        .database()
        .ref(`chats/${chatId}/messages`);

      // Function to get username from user ID
      function getUsername(userId, callback) {
        const userRef = firebase.database().ref(`users/${userId}`);
        userRef.once("value", (snapshot) => {
          const userData = snapshot.val();
          callback(userData.username);
        });
      }
      function formatTimestamp(timestamp) {
        const date = new Date(timestamp);
        return date.toLocaleString(); // Customize the format if needed
      }

      // Load messages ordered by timestamp
      messagesRefForDisplay.on("child_added", (snapshot) => {
        const message = snapshot.val();
        getUsername(message.senderId, (username) => {
          const messageElement = document.createElement("div");
          messageElement.classList.add("message");
          const formattedTimestamp = formatTimestamp(message.timestamp);

          messageElement.innerHTML = `<span class="sender">${username}:</span> ${message.message} <span class="timestamp">(${formattedTimestamp})</span>`;
          document.getElementById("messages").appendChild(messageElement);

          // Auto scroll to the bottom after a new message is added
          document.getElementById("messages").scrollTop =
            document.getElementById("messages").scrollHeight;
        });
      });

      // Send message
      document.getElementById("sendMessage").addEventListener("click", () => {
        const messageInput = document.getElementById("messageInput");
        const messageText = messageInput.value.trim();
        if (messageText) {
          // Use the unfiltered messagesRef for sending
          messagesRefForSending
            .push({
              message: messageText,
              senderId: user.uid, // Use user.uid here
              timestamp: Date.now(),
            })
            .then(() => {
              console.log("Message sent successfully");
            })
            .catch((error) => {
              console.error("Error sending message:", error);
            });
          messageInput.value = ""; // Clear the input
        }
      });
    } else {
      console.log("User is not logged in.");
    }
  });
});

Solution

  • I think you might be experiencing a race condition due to the loading of the user names. A simple fix is to add the element to the HTML straight away, before you start loading the user name:

    // Load messages ordered by timestamp
    messagesRefForDisplay.on("child_added", (snapshot) => {
      const message = snapshot.val();
      const messageElement = document.createElement("div");
      messageElement.classList.add("message");
      document.getElementById("messages").appendChild(messageElement);
      getUsername(message.senderId, (username) => {
        const formattedTimestamp = formatTimestamp(message.timestamp);
    
        messageElement.innerHTML = `<span class="sender">${username}:</span> ${message.message} <span class="timestamp">(${formattedTimestamp})</span>`;
    
        // Auto scroll to the bottom after a new message is added
        document.getElementById("messages").scrollTop =
          document.getElementById("messages").scrollHeight;
      });
    });