Firebase setDoc with typescript

Viewed 136

i want to create a document that has every user that signed in. So i'm creating the document as:

const submitUser = async (
    name: string | undefined | null,
    userId: string | undefined,
    photo: string | undefined | null
  ) => {
    const snapshot: DocumentData = await getDoc(doc(db, "allUsers", "list"));
    const currentUsers: { name: string; uid: string; photo: string }[] =
      snapshot.data().users;

    if (currentUsers.map((item) => item.uid == auth.currentUser?.uid)) return;
    else {
      await setDoc(doc(db, "allUsers", "list"), {
        users: [...currentUsers, { name, uid: userId, avatar: photo }],
      });
      console.log("success");
    }
  };

But if the user exists in the list, then it will just return. I'm calling the function as:

const googleSignIn = () => {
    signInWithPopup(auth, provider).then((res) => {
      setIsAuth(true);
      auth.currentUser &&
        submitUser(
          auth.currentUser.displayName,
          auth.currentUser.uid,
          auth.currentUser.photoURL
        );
    });
  };

But it's not adding new users to the list. What am i doing wrong?

1 Answers

you use map to search for current user - map will return an array of mapped elements which will always be truthy. You can use .some((item) => item.uid == auth.currentUser?.uid) method to seach for current user.

Keep in mind that firebase supports a very low TPS (transactions/requests per seconds) so if you have lots of users logging in this approach may not scale well.

Also keeping current users in a map may be more efficient, you can lookup user by key which is more efficient - O(1) vs O(n)

for example you can keep current user in a document like that:

{
"userid1" : {...user},
"userid2" : {...user},
...
}

in this case to find current user by id you'd have to do just this:


currentUsers[auth.currentUser?.uid] 

this lookup is faster than searching in array (on low volume it's not perceptible though). Another benefit of using a map for your use case: you can use firebase's update method to update information about the current user only, so you don't need to do this:

 users: [...currentUsers, { name, uid: userId, avatar: photo }],

(approach above is also not safe if currentUsers got updated by another client in between calls so you may remove some users with your update.)

you can simplify it to:

update(docRef, {
[auth.currentUser?.uid]:{name, uid: userId, avatar: photo}
});

note that there is no spread operator anymore.

Related