最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Firestore, onSnapshot() or asyncawait issue or both - Stack Overflow

programmeradmin0浏览0评论

I'm trying to get an array of changes using Firebase Firestore's onShapshot().

I'm having trouble retrieving data through onSnapshot(); I may be in trouble with async/await as well, not quite sure...

Can you see where there are problems?

Output should be (but it is currently):

1. New friends: ... // via onSnapshot(). Should not be empty, but it is (However, it does get populated afterwards).
2. All friends: ... // Should not be empty, but it is.
3. Fred's friends: ... // Should not be empty, but it is.

Code:

const getAllFriends = async () => {
    // Gets all friends by connecting to Firestore's onSnapshot stream.

    const getNewFriends = async () => {
        // Sets up a onSnapshot() stream, and returns a newFriends array with their names.
        // Problem: It initially return an empty array, when it shouldn't be empty.

        let newFriends = [];
        await db.collection("user").doc("john").collection("friends").onSnapshot(snapshot => {
            snapshot.docChanges().forEach(change => {
                newFriends.push({ friend: "Emily" });
            });
        });

        console.log("1. New friends: ", newFriends, newFriends.length); // Length should not be 0.
        return newFriends;
    }

    // John starts with no friends:
    let friends = []; 

    // John should now have found some friends:
    let friendChanges = await getNewFriends(); 
    friends = friends.concat(friendChanges);

    console.log("2. All friends:", friends); // Should contain a few Emilys.
    return friends;
};

let johnFriends = await getAllFriends();
console.log("3. John's friends:", friends); // Should contain a few Emilys.

I'm trying to get an array of changes using Firebase Firestore's onShapshot().

I'm having trouble retrieving data through onSnapshot(); I may be in trouble with async/await as well, not quite sure...

Can you see where there are problems?

Output should be (but it is currently):

1. New friends: ... // via onSnapshot(). Should not be empty, but it is (However, it does get populated afterwards).
2. All friends: ... // Should not be empty, but it is.
3. Fred's friends: ... // Should not be empty, but it is.

Code:

const getAllFriends = async () => {
    // Gets all friends by connecting to Firestore's onSnapshot stream.

    const getNewFriends = async () => {
        // Sets up a onSnapshot() stream, and returns a newFriends array with their names.
        // Problem: It initially return an empty array, when it shouldn't be empty.

        let newFriends = [];
        await db.collection("user").doc("john").collection("friends").onSnapshot(snapshot => {
            snapshot.docChanges().forEach(change => {
                newFriends.push({ friend: "Emily" });
            });
        });

        console.log("1. New friends: ", newFriends, newFriends.length); // Length should not be 0.
        return newFriends;
    }

    // John starts with no friends:
    let friends = []; 

    // John should now have found some friends:
    let friendChanges = await getNewFriends(); 
    friends = friends.concat(friendChanges);

    console.log("2. All friends:", friends); // Should contain a few Emilys.
    return friends;
};

let johnFriends = await getAllFriends();
console.log("3. John's friends:", friends); // Should contain a few Emilys.
Share Improve this question edited Apr 15, 2023 at 8:37 Renaud Tarnec 83.2k10 gold badges98 silver badges129 bronze badges Recognized by Google Cloud Collective asked Oct 25, 2020 at 8:29 daCodadaCoda 3,8655 gold badges36 silver badges40 bronze badges 2
  • If you only need to retrieve data then don't use onSnapshot() function instead use .get() method then async await will might work. – Zuhair Naqi Commented Oct 25, 2020 at 8:46
  • 1 did you find an answer to this issue? I seem to be having similar issue. – Penguin Commented Jul 5, 2021 at 14:40
Add a ment  | 

2 Answers 2

Reset to default 3

Have a look at this answer which explains the difference between the get() and onSnapshot() methods.

In a nutshell:

  • When you use get() you retrieve all the documents of the collection only once (like a "get and forget").
  • When you use onSnapshot() you constantly listen to the collection.

Note that onSnapshot() is not an asynchronous method, while get() is => don't call onSnapshot() with await.


Since, from your question, it seems that you want to get the list of friends by calling the getAllFriends() method, do as follows:

  const getAllFriends = async (userName) => {
    const querySnapshot = await db
      .collection('user')
      .doc(userName)
      .collection('friends')
      .get();
    return querySnapshot;
  };

  let johnFriends = await getAllFriends('john');
  johnFriends.forEach(doc => {
    console.log(doc.id, ' => ', doc.data());
  });

More possibilities are to be found in the Firestore doc, here and here.

I think you just want to track newly added John's friends and add them to the johnFiends array. Perhaps you can just add the onsnapshot listener on top of @Renaud's suggestion:

const getAllFriends = async (userName) => {
    const querySnapshot = await db
      .collection('user')
      .doc(userName)
      .collection('friends')
      .get();
    // You may need check for querySnapshot.empty before proceed
    let allFriends = querySnapshot.docs.map(doc => doc.data());
    return allFriends;
  };

let johnFriends = await getAllFriends('john');
console.log("All John's friends:", johnFriends);

const unsubscribe = db.collection("user").doc("john").collection("friends")
    .onSnapshot(snapshot => {
        snapshot.docChanges().forEach(change => {
            if (change.type === "added") {
                johnFriends.push(change.doc.data());
                console.log("New John's friend:", change.doc.data());
                console.log("New all John's friends:", johnFriends);
            };
        });
    });

Note that onsnapshot is mostly for real-time tracking of data change at the backend and what you should do later in the frontend, therefore you should apply it on real-time handler instead of incorporate it inside a normal data pulling function, e.g. getAllFriends(). In short, handle real-time changes separately.

发布评论

评论列表(0)

  1. 暂无评论