Search code examples
javascriptfirebasevariablesgoogle-cloud-firestoreconstants

Can't make Firestore to get only docs from logged user id


I am an UX Designer and I'm pretty new to working with Firebase.

I've been trying to develop a system on webflow integrated with Firebase using JavaScript and the Firebase SDK to a personal project and got stuck with this problem.

I have managed to create the authentication system, the signup system and everything is working as it should.

However, when I try to fetch data from Firestore userdata collection, I am not being able to get the current user id and pass it to the WHERE string on my query.

If I run the query without the WHERE, it works perfectly, bringing me all the documents in the userdata collection, but when I try to do it only for a specific user, it fails.

I already tried a lot of things which I think wasn't the right method to do this, the JavaScript below was my last attempt. I think I'm just too new on this and can't understand how to pass the id variable into the query.

Here is the link to the project: https://poupei.webflow.io/. Just click "Criar conta" to create an account, you can use a fake email and 6 digit password and then login.

  // Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.4.0/firebase-app.js";
import { getAuth, onAuthStateChanged, signOut } from "https://www.gstatic.com/firebasejs/9.4.0/firebase-auth.js";
import { getFirestore, collection, getDocs, query, where, doc } from "https://www.gstatic.com/firebasejs/9.4.0/firebase-firestore.js"


// TODO: Add SDKs for Firebase products that you want to use
  // https://firebase.google.com/docs/web/setup#available-libraries

  // Your web app's Firebase configuration
 const app = initializeApp({
    apiKey: "AIzaSyAZUIyxf4Lsw6D9JOzVuNslsGJ8gXkPBVY",
    authDomain: "poupei-app.firebaseapp.com",
    projectId: "poupei-app",
    storageBucket: "poupei-app.appspot.com",
    messagingSenderId: "837432279066",
    appId: "1:837432279066:web:119bc86e42fb87ac17d1a3"
});

  // Initialize Firebase
  const auth = getAuth()
  const db = getFirestore();
  onAuthStateChanged(auth, (user) => {
  if (user) {
    // User is signed in, see docs for a list of available properties
    // https://firebase.google.com/docs/reference/js/firebase.User
    const userID = user.id;
    console.log("Logged In");
    console.log(userID);
    // ...
  } else {
    // User is signed out
    window.location.replace("https://poupei.webflow.io/");
  }
});

const q = query(collection(db, "userdata"), where("id", "==", userID));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
  // doc.data() is never undefined for query doc snapshots
  console.log(doc.id, " => ", doc.data());
  const docs = doc.data();
   document.getElementById('nome').innerHTML = docs.nome;
   document.getElementById('sobrenome').innerHTML = docs.sobrenome;
   document.getElementById('email').innerHTML = docs.email;
   document.getElementById('saldo').innerHTML = docs.saldo;
});

 document.getElementById('logoutBtn').addEventListener('click', function(){
  signOut(auth).then(() => {
  // Sign-out successful.
  window.location.replace("https://poupei.webflow.io/");
}).catch((error) => {
  // An error happened.
});
});

</script>

´´´

Solution

  • @Allennick has the cause of the problem correct in their answer, but the solution won't work.


    Signing in to Firebase (as well as loading data from Firestore and most other modern cloud APIs) is an asynchronous operation. While the user is being signed in (or the data is being loaded) your main code continues to run. Then when the user is signed in, your callback code is executed.

    It's easiest to see this flow by running in a debugger, or adding some logging:

    console.log("Attaching auth state listener");
    onAuthStateChanged(auth, (user) => {
      if (user) {
        console.log("Got user state");
      }
    });
    
    console.log("Starting database query");
    const q = query(collection(db, "userdata"), where("id", "==", userID));
    const querySnapshot = await getDocs(q);
    

    When you run this code it logs:

    Attaching auth state listener

    Starting database query

    Got user state

    This is probably not the order you expected, but it perfectly explains why you're not getting the user data from the database: the query executes before the user is ever loaded.


    The solution to this problem is always the same: any code that needs to react to the current user state, needs to be inside the onAuthStateChanged callback, be called from there, or otherwise synchronized.

    The simplest fix is to move your database code into the callback, like this:

    onAuthStateChanged(auth, async (user) => {
      if (user) {
        const userID = user.id;
    
        // 👇 Now that the user us know, we can load their data
        const q = query(collection(db, "userdata"), where("id", "==", userID));
        const querySnapshot = await getDocs(q);
        querySnapshot.forEach((doc) => {
          // doc.data() is never undefined for query doc snapshots
          console.log(doc.id, " => ", doc.data());
          const docs = doc.data();
           document.getElementById('nome').innerHTML = docs.nome;
           document.getElementById('sobrenome').innerHTML = docs.sobrenome;
           document.getElementById('email').innerHTML = docs.email;
           document.getElementById('saldo').innerHTML = docs.saldo;
        });
        
        document.getElementById('logoutBtn').addEventListener('click', function(){
          signOut(auth).then(() => {
          // Sign-out successful.
          window.location.replace("https://poupei.webflow.io/");
        }).catch((error) => {
          // An error happened.
        });
      } else {
        // User is signed out
        window.location.replace("https://poupei.webflow.io/");
      }
    });
    

    Also see: